app
Parts Search
Public Made by Adomby adom
One search box across Mouser, DigiKey and JLCPCB: parallel queries, side-by-side product photos, and a Mouser-preferred recommendation that reasons around stock and lead time.
← Commit history
Publish v1.0.1 package: install/uninstall scripts, skills, manifest
6 files changed
+285−20
install.sh+14−13@@ -1,15 +1,16 @@ #!/bin/bash-set -e-PKG_DIR="$(cd "$(dirname "$0")" && pwd)"-SKILLS_DIR="$HOME/.claude/skills"-mkdir -p "$SKILLS_DIR/adom-parts-search"-if [ -f "$PKG_DIR/SKILL.md" ]; then- cp "$PKG_DIR/SKILL.md" "$SKILLS_DIR/adom-parts-search/SKILL.md"-fi-for skill_dir in "$PKG_DIR/skills"/*/; do- [ -d "$skill_dir" ] || continue- skill_name=$(basename "$skill_dir")- mkdir -p "$SKILLS_DIR/$skill_name"- cp -r "$skill_dir"* "$SKILLS_DIR/$skill_name/"+# install.sh for adom-parts-search (app) β runs from the extracted module dir.+set -euo pipefail+DIR="$(cd "$(dirname "$0")" && pwd)"; cd "$DIR"+BIN_DIR="${HOME}/.local/bin"; mkdir -p "$BIN_DIR"+install -m 0755 "$DIR/bin/adom-parts-search" "$BIN_DIR/adom-parts-search"+echo "Installed adom-parts-search -> $BIN_DIR/adom-parts-search"+SKILL_DIR="${HOME}/.claude/skills"+for s in adom-parts-search adom-parts-search-build; do+ if [ -f "$DIR/skills/$s/SKILL.md" ]; then+ mkdir -p "$SKILL_DIR/$s"+ install -m 0644 "$DIR/skills/$s/SKILL.md" "$SKILL_DIR/$s/SKILL.md"+ echo "Installed skill -> $SKILL_DIR/$s/SKILL.md"+ fi done-echo "Installed adom-parts-search"+echo "adom-parts-search installed. Try: adom-parts-search --help"
package.json+33−3@@ -1,7 +1,37 @@ { "slug": "adom-parts-search",- "version": "1.0.0",+ "version": "1.0.1", "type": "app", "description": "One search box across Mouser + DigiKey + JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-min drone delivery to Fort Worth) that reasons around stock and lead time.",- "dependencies": {}-}+ "dependencies": {},+ "tags": [+ "parts-search",+ "mouser",+ "digikey",+ "jlcpcb",+ "bom",+ "sourcing",+ "distributor",+ "electronics",+ "open-source",+ "mit"+ ],+ "license": "MIT",+ "needs_sudo": false,+ "scripts": {+ "install": "./install.sh",+ "uninstall": "./uninstall.sh"+ },+ "files": [+ "bin/**",+ "skills/**",+ "install.sh",+ "uninstall.sh",+ "package.json",+ "page.json",+ "README.md",+ "SKILL.md",+ "BUILD-SKILL.md",+ "screenshots/**"+ ]+}
page.json+1−1@@ -4,7 +4,7 @@ "slug": "adom-parts-search", "title": "Adom Parts Search", "brief": "One search box across Mouser + DigiKey + JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-min drone delivery to Fort Worth) that reasons around stock and lead time.",- "version": "1.0.0",+ "version": "1.0.1", "install": { "binary_name": "adom-parts-search", "install_dir": "",
skills/adom-parts-search-build/SKILL.mdadded+47@@ -0,0 +1,47 @@+---+name: adom-parts-search-build+description: Build and release a new version of adom-parts-search. Use when the user says "release adom-parts-search", "publish adom-parts-search", "cut a new adom-parts-search version", "bump adom-parts-search", "ship adom-parts-search".+---++# Release adom-parts-search++1. Bump `VERSION` + `Cargo.toml` + `wiki/page.json` version.+2. `./build.sh` β cargo build, install local binary.+3. Verify β `adom-parts-search search "STM32F103RBT6"` returns all three vendors.+4. Ralph-loop the webview (`adom-parts-search app --no-tab` + pup).+5. Show user a screenshot of the 3-column grid + recommendation banner; wait for explicit approval.+6. `./publish.sh` β git tag, wiki asset upload, wiki page update, verify.++## Pre-release checklist++- [ ] VERSION / Cargo.toml / `--version` / wiki metadata all match+- [ ] All three backends reachable (check service-watcher)+- [ ] Recommendation banner renders Mouser-preferred when Mouser is in stock+- [ ] Product images render (web-view fetches mouser.com + digikey.com + LCSC images)+- [ ] No console errors via `GET /console`+- [ ] π Icon audit β EVERY icon monochrome white, no favicon carve-out.+ Run all three greps; each must return zero:+ ```+ # (a) Teal fills/strokes in any SVG, including docs/icon.svg itself+ grep -nE 'fill="(#00b8b0|#00d4cb)"|stroke="(#00b8b0|#00d4cb)"' \+ docs/icon.svg src/app/*.html src/app/*.svg 2>/dev/null++ # (b) docs/icon.svg uses only #e6edf3 / currentColor / none / bg-dark+ grep -oE 'fill="#[0-9a-fA-F]{3,8}"|stroke="#[0-9a-fA-F]{3,8}"' docs/icon.svg | \+ grep -v -E '"#e6edf3"|"#ffffff"|"#fff"|"#0d1117"|"none"|"transparent"|"currentColor"' \+ || echo "(docs/icon.svg clean)"++ # (c) No .logo / .icon container inheriting --accent as currentColor+ grep -nE '\.logo[^{]*{[^}]*color:\s*var\(--accent\)|\.icon[^{]*{[^}]*color:\s*var\(--accent\)' \+ src/app/*.html 2>/dev/null+ ```+ The favicon/tab-icon is NOT exempt. See `brand/SKILL.md` Β§Icons ++ `app-creator/SKILL.md` Β§1b β the rule was tightened after this+ app shipped v0.1.0 with a teal tab icon that slipped past three+ audits.++## Version bumping triggers++- Backend URL changes (slug rotation on service-mouser / service-digikey / service-jlcpcb) β patch bump + republish to propagate.+- UI changes visible to the user β minor bump.+- Policy changes (e.g. new vendor, different preference rules) β minor bump + update the gallia `adom-parts-search` skill to match.
skills/adom-parts-search/SKILL.mdadded+186@@ -0,0 +1,186 @@+---+name: adom-parts-search+description: Unified parts search across Mouser + DigiKey + JLCPCB with Mouser-preferred routing (40-min drone delivery from Mansfield, TX to our Fort Worth facility; near-zero shipping). CLI and Hydrogen webview app. Use when the user asks to source a part, price a component, compare vendors, check stock across distributors, or assemble a BOM. Trigger words β find part, search parts, source component, parts search, component search, where can I get, compare distributors, Mouser or DigiKey, compare prices, BOM sourcing, stock check, parts availability, open parts search, parts search app, parts search UI.+---++# adom-parts-search++Searches Mouser + DigiKey + JLCPCB in parallel. Rust CLI + Hydrogen webview. Recommends **Mouser by default** because our Fort Worth facility has a 40-minute drone delivery arrangement with Mouser's Mansfield, TX fulfillment center + near-zero shipping cost.++## CLI++**For user-facing searches, always use `show`.** It drives the webview tab AND prints the full vendor-by-vendor result to stdout, so the user sees product photos + 3-column comparison and the AI sees the same data textually. Auto-starts the app server + opens the tab on first run.++```bash+# β DEFAULT β every search a human asks for+adom-parts-search show "ESP32-S3-WROOM-1U-N4R2"+adom-parts-search show "iCE40HX4K-TQ144" --limit 8 --in-stock-only++# Scripting / piping / batch only (no webview, pure JSON)+adom-parts-search search "STM32F103RBT6" | jq '.recommendation'++# Keep the app tab running without triggering a search+adom-parts-search app+```++### Decision rule++- User asked a conversational question about a part β **`show`**. Always.+- You're piping into `jq`, `awk`, or a batch script β `search`.+- Silence: never just dump JSON to chat. If you would have run `search`, run `show` instead β the user wants photos and side-by-side comparison, not a wall of JSON.++### Extract a clean MPN / part-family BEFORE calling `show`++Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, NOT full-text intent search. If the user says "find me a 3.3V LDO with 500 mA", do NOT pipe `"find me a 3.3V LDO with 500 mA"` into `show` β that's natural language, and every vendor will return zero hits. Extract the likely part family or MPN first, then call `show`.++**Extraction examples:**++| User said | Pass to `show` | Why |+|---|---|---|+| "find me a 555 timer" | `LM555` | Canonical 555-family part. Also try `NE555` if no hits. |+| "search for esp32 dev boards" | `ESP32` | Broad family match; narrow later with `ESP32-S3` if the user wants a specific variant. |+| "need a 3.3V LDO 500mA" | `LM1117-3.3` or `AMS1117-3.3` | Well-known 3.3V LDOs; pick one, try the other if empty. |+| "stm32 bluepill chip" | `STM32F103C8T6` | The canonical Blue Pill MCU. |+| "what op-amp for unity gain audio" | `TL072` or `NE5532` | Common audio op-amps. Don't pass "op-amp audio" as a keyword. |+| "lm333 timer" | Ask first β LM333 isn't a 555-family timer. Probably `LM555` (typo). | Don't burn a search on a bogus part number. |++**Rules of thumb:**++- If the user typed a clearly valid MPN (has letters + digits + optional dash, 4+ chars, looks like `STM32F103RBT6` / `LM555` / `ESP32-S3-WROOM-1U-N4R2`), pass it through verbatim.+- If the user typed a natural-language description, mentally map it to the 1-2 best-known part families and pass the first one to `show`. If that returns 0, try the second.+- If the user named a part that doesn't match a family you recognize (`LM333` for "timer"), **stop and ask one clarifying question** before searching β don't guess your way into a bogus API call.+- If the user names an exact variant (e.g. "ESP32-S3-WROOM-1U-N4R2"), use that; don't broaden it unless a search returns 0.++### Handling empty results++If `show` returns 0 hits across all three vendors AND no vendor errored, the CLI will already print a helpful "no matches" line and the webview will render an empty-state card with suggestions. You still need to decide what to do next:++1. Try one alternative family name (e.g. `LM555` β `NE555` β `LM556`).+2. If the alternative also returns 0, surface that to the user with a brief explanation: "Neither LM555 nor NE555 matched β double-check the MPN or describe the part differently."+3. Do NOT silently run five searches in a row with minor variations β ask the user for a better name after the second attempt.++### Common part families + corrections++| If the user saidβ¦ | Try first | Also valid |+|---|---|---|+| "555 timer" / "monostable timer" | `LM555` | `NE555`, `LM556`, `TLC555` |+| "3.3V LDO" | `LM1117-3.3` | `AMS1117-3.3`, `AP2112K-3.3` |+| "5V LDO" | `LM7805` | `LM1117-5.0`, `AMS1117-5.0` |+| "op-amp" (audio) | `TL072` | `NE5532`, `OPA2134` |+| "op-amp" (general) | `LM358` | `MCP6002`, `TL074` |+| "FPGA" (Lattice ice40 family) | `iCE40HX4K-TQ144` | `iCE40UP5K`, `iCE40LP1K` |+| "ESP32" (generic) | `ESP32-WROOM-32` | `ESP32-S3`, `ESP32-C3` |+| "STM32 Blue Pill" | `STM32F103C8T6` | `STM32F103RBT6` |+| "Arduino Nano MCU" | `ATmega328P` | `ATmega168` |+| "USB-C connector" | `USB4085` | `USB4110`, `GCT USB4105` |++If you see the user invoke a part number that doesn't look right (like `LM333` for "timer"), consult this table FIRST, ask a one-line clarifying question, and only call `show` after the user confirms the correction.++Stdout from `show` looks like:++```+adom-parts-search keyword: "iCE40HX4K-TQ144"++MOUSER total= 1 hits= 1 412ms [ok]+ iCE40HX4K-TQ144 Lattice Semiconβ¦ $10.20 stock 42+DIGIKEY total= 1 hits= 1 676ms [ok]+ ICE40HX4K-TQ144 Lattice Semiconβ¦ $11.22 stock 413+JLCPCB total= 0 hits= 0 74ms [ok]++RECOMMENDATION β Mouser iCE40HX4K-TQ144 $10.20 stock 42+ Mouser stocked β 40-min drone delivery from Mansfield.+```++followed by the full unified JSON (same schema as `search` below) so downstream tooling has structured access.++The `search` output is a unified JSON:++```json+{+ "query": "iCE40HX4K-TQ144",+ "mouser": { "ok": true, "total": 1, "hits": [...], "elapsed_ms": 412 },+ "digikey": { "ok": true, "total": 1, "hits": [...], "elapsed_ms": 630 },+ "jlcpcb": { "ok": true, "total": 0, "hits": [], "elapsed_ms": 180 },+ "recommendation": {+ "winner": "Mouser",+ "mpn": "iCE40HX4K-TQ144",+ "unit_price": "$10.20",+ "stock": 42,+ "reason": "Mouser stocked β 40-min drone delivery from Mansfield, near-zero shipping."+ }+}+```++Each `hit` includes `image_url` for the webview β use the `app` subcommand when the user needs to eyeball product photos (Claude Code terminal can't show images).++## Webview app++`adom-parts-search app` opens a Hydrogen tab titled **"Parts Search"** with a 3-column grid:++- **Mouser column** (blue top border) β preferred, badged "40-min drone Β· $0 ship"+- **DigiKey column** (red top border) β alternative+- **JLCPCB column** (green top border) β parts library only (SMT assembly)++Each card shows the product photo, MPN, vendor PN, manufacturer, price (@1 and @100), stock, lead time, flags (RoHS / basic / preferred / lifecycle). Click any product photo to zoom.++The recommendation banner at the top calls out the winning vendor with the reason β the same policy as the CLI, rendered visually.++## Pin-1 alignment check β moved to `adom-chipfit`++The footprint β 3D-chip validator that used to live here as+`adom-parts-search align` is now its own app: **`adom-chipfit`**.+Scope got big enough (package-family guard, seat-Ξz classifier,+persistent pin-1 registration bake) that keeping it inside+parts-search was mixing two unrelated concerns.++Install one-liner (paste-into-Claude style):++```bash+curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-chipfit/adom-chipfit \+ -o /tmp/adom-chipfit && chmod +x /tmp/adom-chipfit \+ && sudo install -m 0755 /tmp/adom-chipfit /usr/local/bin/adom-chipfit \+ && adom-chipfit install+```++Then use it via:++```bash+adom-chipfit check --footprint path.kicad_mod --glb path.glb+```++Running `adom-parts-search align ...` now prints a one-time message+pointing at the install command above and exits non-zero so CI+picks it up.++## Why Mouser is preferred++See the companion skill `adom-parts-search` (the gallia one) for the full policy. Short version:++- **40-minute drone delivery** (Mansfield TX β Fort Worth TX, ~15 miles)+- **Near-zero shipping cost** (drone route, Mouser-operated)+- DigiKey wins only when Mouser is out of stock, lead time >14 days, or DigiKey is >30% cheaper on a volume order++## Backend URLs++The three vendor backends are Tier A services. Current URLs:++- Mouser: `https://mouser-xr8t4f5d01bt.adom.cloud`+- DigiKey: `https://digikey-gjuu8l5t69uh.adom.cloud`+- JLCPCB: `https://jlcpcb-wela51osctvp.adom.cloud`++Override with `--mouser-api` / `--digikey-api` / `--jlcpcb-api`, or env vars `MOUSER_API` / `DIGIKEY_API` / `JLCPCB_API`. Canonical source of truth for current slugs is `~/service-watcher/services.json` on the main gallia container.++## Architecture++This app is **client-only** β no service container of its own. It coordinates the three existing vendor backends (adom-mouser / adom-digikey / adom-jlcpcb). Each individual vendor CLI is still available for single-vendor queries.++## Install++Tier A β fetched by `gallia/install.mjs` on every gallia container. Or manually:++```bash+curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-parts-search/adom-parts-search \+ -o /tmp/adom-parts-search && chmod +x /tmp/adom-parts-search && \+ sudo install -m 0755 /tmp/adom-parts-search /usr/local/bin/adom-parts-search && \+ adom-parts-search install+```
uninstall.sh+4−3@@ -1,4 +1,5 @@ #!/bin/bash-set -e-rm -rf "$HOME/.claude/skills/adom-parts-search"-echo "Uninstalled adom-parts-search"+set -euo pipefail+rm -f "${HOME}/.local/bin/adom-parts-search"+rm -rf "${HOME}/.claude/skills/adom-parts-search" "${HOME}/.claude/skills/adom-parts-search-build"+echo "Removed adom-parts-search"