claude/skills/bestbuy/SKILL.md
Search Best Buy for products, find open box deals, and check per-store inventory at nearby Best Buy locations. Use whenever the user asks about Best Buy prices, open box deals, store availability, finding products at Best Buy, comparing Best Buy with Amazon or other retailers, MacBook Pro/laptop/camera/TV deals at Best Buy, or whether specific items are physically in stock at nearby Best Buy stores. Also use when user mentions "open box" without specifying a retailer (Best Buy is the major US retailer with a real open box program).
npx skillsauth add kendreaditya/.config bestbuyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A skill for finding the best deals at Best Buy — combining new prices, open box prices across all conditions (Fair/Good/Excellent), and real per-store physical inventory at user's nearby stores.
This skill is powered by the bestbuy CLI tool (installed at ~/.local/bin/bestbuy, source at ~/.config/scripts/bestbuy).
bestbuy --help # show subcommands
bestbuy stores 33620 # nearest Best Buy stores
bestbuy search "macbook pro 14" --zip 33620 --brand Apple # search + open box prices
bestbuy stock "macbook pro 14" --zip 33620 # per-store physical inventory
bestbuy stock --skus 6602748,6615860 --zip 33620 # check specific SKUs
The stock subcommand is the killer feature — it tells you which specific store has each open box unit physically on the shelf vs which need ship-to-store.
BBY_API_KEY env varrequests, click, and playwright (auto-loaded via _utils.ensure_config_venv())/opt/pw-browsers/chromium-1194/... if available, else defaultThese are the specific bugs and limitations that wasted hours. The bestbuy CLI handles all of these correctly. Don't rewrite the logic without understanding them:
The endpoint beta/products/openBox(sku in(SKU1,SKU2,...)) is supposed to accept up to 100 SKUs in one call, but silently drops most results when batched. Out of 27 MacBook SKUs in one batch query, only 10 came back. Querying each SKU individually returned 20+. Always loop:
for sku in skus:
r = requests.get(f"https://api.bestbuy.com/beta/products/openBox(sku in({sku}))",
params={"apiKey": API_KEY, "format": "json"}, timeout=10)
time.sleep(0.5) # rate limit
OPEN_BOX_EXCELLENT vs excellentThe beta API returns conditions as lowercase: "excellent", "good", "fair".
The GraphQL fulfillment endpoint requires uppercase with prefix: "OPEN_BOX_EXCELLENT", "OPEN_BOX_GOOD", "OPEN_BOX_FAIR".
graphql_cond = f"OPEN_BOX_{api_cond.upper()}" # excellent -> OPEN_BOX_EXCELLENT
If you forget this, the GraphQL endpoint returns errors silently and every store shows as "unavailable." This was a subtle bug that hid real per-store data.
Two ways to query the GraphQL fulfillment endpoint return different things:
Wrong way — searchNearby: true, showNearbyLocations: true returns the same instoreInventoryAvailable value for ALL stores. Just a global "exists in network" flag.
Right way — query each store INDIVIDUALLY without searchNearby:
variables = {
"fulfillmentOptionsInput": {
"sku": sku,
"condition": "OPEN_BOX_EXCELLENT", # MUST be the OPEN_BOX_X format
"inStorePickup": {"storeId": store_id}, # NO searchNearby
"shipping": {"destinationZipCode": zip, "effectivePlanPaidMembership": "NULL"},
"buttonState": {"context": "PDP", "destinationZipCode": zip,
"storeId": store_id, "effectivePlanPaidMembership": "NULL"},
}
}
url = f"https://www.bestbuy.com/gateway/graphql/fulfillment?variables={urllib.parse.quote(json.dumps(variables))}"
Check data.fulfillmentOptions.ispuDetails[0].ispuAvailability[0].instoreInventoryAvailable. When true, the unit is physically at THAT store. When false but pickupEligible: true, ship-to-store works.
Button state interpretation:
ADD_TO_CART = available for purchase (likely on shelf or shippable)CHECK_STORES = exists somewhere but NOT at this specific storeSOLD_OUT = no units anywhereNOT_AVAILABLE = condition doesn't exist/gateway/graphql, but GET to /gateway/graphql/fulfillment worksThe richer MarketplaceBuyingOptions query is a POST and gets blocked by Akamai TLS fingerprinting (especially through proxies). Stick with the GET fulfillment endpoint — it's enough to determine per-store availability via the instoreInventoryAvailable flag.
%20, not +# Bad — returns 400 errors:
url = "https://api.bestbuy.com/v1/products(search=macbook+pro+14)"
# Good:
url = "https://api.bestbuy.com/v1/products(search=macbook%20pro%2014)"
time.sleep(0.3-0.5) between callspageSize=100, page=1 and filter locallyIf HTTPS_PROXY env var is set (cloud sandboxes), pass it to Chromium:
proxy_url = os.environ.get("HTTPS_PROXY")
if proxy_url:
pp = urlparse(proxy_url)
proxy_cfg = {"server": f"http://{pp.hostname}:{pp.port}",
"username": pp.username or "", "password": pp.password or ""}
browser = p.chromium.launch(headless=True, proxy=proxy_cfg, ...)
Without this, you get ERR_INVALID_AUTH_CREDENTIALS on every page load.
The beta API caches prices and may show open box deals that are actually sold out everywhere. Always verify availability via the per-store check before recommending a deal. A $706 M3 MacBook Pro that's sold out nationwide is misleading. The bestbuy stock subcommand handles this by showing real button states (SOLD vs STOCK vs ship).
Just run bestbuy stock. It does:
v1/stores(area(ZIP,100))v1/products(search=...&active=true), filter to keyword matchesIf the user shares Amazon prices (screenshots, copy/paste), build a side-by-side table. Best Buy usually wins on:
Amazon usually wins on:
For per-store inventory results, present as:
| Price | Model | Condition | Store(s) with unit on shelf |
|-------|-------|-----------|------------------------------|
| $1,587 | M4 Pro 24GB/512GB | Fair | Wesley Chapel [1405] |
Include the store ID in brackets — useful if user wants to call.
| Endpoint | Method | What it returns |
|----------|--------|-----------------|
| v1/stores(area(ZIP,MILES)) | GET | Nearby stores (id, name, distance, hours, phone) |
| v1/products(search=QUERY&...) | GET | Product catalog search |
| v1/products/{sku}.json | GET | Single product full details |
| v1/categories(name=PATTERN) | GET | Category tree |
| beta/products/openBox(sku in(SKU)) | GET | Open box prices + conditions |
| gateway/graphql/fulfillment?variables=... | GET | Per-store fulfillment + inventory |
| ID | Name | City | |----|------|------| | 561 | South Tampa | Tampa | | 462 | Citrus Park | Tampa | | 560 | Brandon | Brandon | | 564 | Clearwater | Clearwater | | 565 | St. Petersburg | St Pete | | 1405 | Wesley Chapel | Wesley Chapel | | 885 | Port Richey | Port Richey | | 563 | Lakeland | Lakeland |
development
Search and read content from leetcode.com — problem catalog, daily challenge, full problem statements with hints and starter code, the Discuss forum (interview experiences, comp posts, layoff threads), and company question-list metadata. Read-only, no auth, no API key. Use when the user wants to look up a LeetCode problem by name/number/slug, see today's daily challenge, search Discuss for interview write-ups at a specific company (Google, Waymo, Meta, Amazon, etc.), browse a tag-filtered discuss feed, read a Discuss post + comments, or check what a LeetCode company list covers. Triggers — "lcsearch", "leetcode search", "search leetcode", "leetcode discuss", "leetcode problem", "daily leetcode", "interview discuss", "what's the leetcode for X", URLs containing leetcode.com/problems/, leetcode.com/discuss/, or leetcode.com/company/. Pair with the `interviewcoder` skill (structured leetcode-style writeups from 1point3acres) and `blind` (anonymous workplace chatter) for the same companies.
development
Terminal Spotify playback/search via spogo (preferred) or spotify_player.
development
Search and read posts from interviewcoder.co — a Next.js-fronted aggregator of technical-interview writeups (largely sourced from 1point3acres) tagged by company, position, stage (Phone Screen / OA / Onsite / etc.), period, job type, and structured leetcode-style questions. Use when the user wants real interview questions for a specific company, recent writeups from a hiring loop, leetcode-style problems with tags and difficulty, or to look up a specific interviewcoder.co URL. Read-only, no auth, no API key. Triggers — "interviewcoder", "interviewcoder.co", "interview questions at [company]", "what's been asked at [company] recently", "interview writeup", and URLs containing interviewcoder.co.
tools
Small Yahoo Finance CLI for ticker info + N-year stock returns. Use when the user asks about: stock price, market cap, sector/industry classification, dividend yield, P/E ratio, beta, 52-week range, N-year stock return, company description for a public company. Triggers: 'yfinance', 'yfin', 'stock price', 'market cap of', 'how much has X stock returned', 'sector for ticker', 'industry classification'. Pairs with the levels-fyi skill for cross-checking public/private status (levels gives ticker, yfin returns live data).