← Commit history
playbooks/adom-desktop-api.mdadded+355
@@ -0,0 +1,355 @@+# adom-desktop API patterns (chip-fetcher playbook)++Trusted clicks, popup auto-tracking, smart-pick, browser_fetch_url, pull_file. Read this when you need to drive a pup browser tab beyond the basic `browser_navigate` + `browser_eval` couplet.++## Trusted click via `browser_input_dispatch` (adom-desktop ≥ v1.4.7)++When a click "lands but does nothing" — that's almost always because the framework / vendor JS gates the handler on `event.isTrusted`, and page-side `dispatchEvent(new MouseEvent(...))` is `isTrusted: false`. **`browser_input_dispatch` routes through Chromium CDP `Input.dispatchMouseEvent` / `dispatchKeyEvent`** — events have `isTrusted: true`, so framework handlers (React/Vue/Svelte) and most vendor anti-automation gates actually fire.++```bash+# Click by selector (preferred — uses element bounding rect + scrollIntoView)+adom-desktop browser_input_dispatch '{+  "sessionId":"chip-fetcher",+  "type":"click",+  "selector":"button.wg-button--primary"+}'++# Click by viewport coords+adom-desktop browser_input_dispatch '{+  "sessionId":"chip-fetcher",+  "type":"click",+  "x":860, "y":803+}'++# Type into an input+adom-desktop browser_input_dispatch '{+  "sessionId":"chip-fetcher",+  "type":"type",+  "text":"DMG2305UX-7",+  "selector":"input[name=search]"+}'++# Press a key+adom-desktop browser_input_dispatch '{+  "sessionId":"chip-fetcher",+  "type":"key",+  "key":"Enter"+}'++# Mouse move (human-like trajectory before a click)+adom-desktop browser_input_dispatch '{+  "sessionId":"chip-fetcher",+  "type":"move",+  "x":400, "y":500, "steps":10+}'+```++Optional fields: `tabId` (defaults to active tab), `button` (`left`|`right`|`middle`), `clickCount` (2 for double-click), `delay` (ms between mousedown/mouseup or between keystrokes).++**Use `browser_input_dispatch` when:**+- Vendor "Generate" / "Download" / "Submit" buttons no-op on `browser_eval` clicks+- Login forms behind framework gates+- Modal dismissal needs `key:"Escape"` and DOM-level dispatch fails+- Any time you'd say "I clicked it but nothing happened"++`browser_eval`-side click is still fine for buttons that DO fire (most CSE Download Model buttons, simple modal openers). `browser_input_dispatch` is the upgrade path when those silently no-op.++## Popup tabs auto-track in `browser_list_tabs` (adom-desktop ≥ v1.4.7)++Tabs the page itself spawns (`window.open()`, `target="_blank"` form submits, `<a target="_blank">` clicks) used to be invisible. Now they auto-track:++```bash+adom-desktop browser_list_tabs '{"sessionId":"chip-fetcher"}'+# → tabs: [+#     { tabId:"tab-1", opener:"user",  openerTabId:null,    url:"..." },+#     { tabId:"tab-2", opener:"popup", openerTabId:"tab-1", url:"..." }+#   ]+```++`opener:"user"` = chip-fetcher opened it. `opener:"popup"` = the page spawned it; `openerTabId` names the tab that triggered the popup.++Popups don't auto-focus — use `browser_switch_tab` to make one active before screenshots, or pass `tabId` to `browser_eval` / `browser_screenshot` to target it without switching.++## Clicks may open the result in a NEW TAB++**Every "Download Datasheet" / "Generate" / "Open PDF" / "View Document" click on a vendor site can spawn a new browser tab.** Common sites where this fires: WAGO ("Generate Datasheet" → PDF in new tab), Microchip, ST, Renesas, ADI, even some TI app-note rows.++**The rule, applied after every click that "should" produce a download/PDF/CAD file:**++1. **Wait ~2-5s** for the popup to fully load (it may be a redirect chain).+2. **`browser_list_tabs`** — look for a new entry with `opener:"popup"`. The `openerTabId` confirms which tab triggered it.+3. **`browser_eval` (or `browser_screenshot`) with `tabId` set to the popup's `tabId`** — interact with the popup directly without switching the active tab.+4. **For a PDF popup**: grab `location.href` from the popup, then use `browser_fetch_url` (Mode A or B). Do NOT use in-page `fetch(location.href)` on a Chrome PDF Viewer popup — it returns the PDF Viewer HTML wrapper (~200 KB stub), not the binary.+5. **`browser_close_tab` with the popup's `tabId`** to clean up after.++This also applies to "Buy" → distributor checkout, "View 3D" → embedded viewer in new tab, "Open Application Note" → PDF in new tab.++Direct user pushback: *"wago opens the datasheet in a new tab, so you could just see that tab and then save it locally"* + *"add that to the skill that this could happen on any website."*++## Smart-pick (adom-desktop ≥ v1.4.9)++When a selector matches multiple elements, the relay no longer silently picks document-order first. It filters to visible+text matches, detects open modals, and prefers candidates **inside** the topmost modal (with area tiebreak).++Always check the response fields:++```json+{+  "ok": true,+  "matchedCount": 4,+  "chosenIndex": 3,+  "clickedRect": {"x":890,"y":803,"w":193,"h":48},+  "clickedText": "Generate data sheet",+  "pickStrategy": "modal-scoped-largest",+  "modalDetected": true,+  "insideModal": true+}+```++`pickStrategy` values to act on:+- `only-match` / `first-match` — single match, or you opted out via `firstMatch:true`+- `modal-scoped-largest` — modal detected, picked inside it (preferred)+- `visible-text-largest` — no modal, area-tiebreak among visible+text+- `visible-text-largest-no-modal-match` — modal detected but selector hit nothing inside it. **Either your selector is wrong, OR modal-detection misfired (Vue-Toastification false-positive bug).**+- `visible-largest` — no text matches, fell back to area+- `fallback-first-document-order` — nothing visible at all++If `pickStrategy` is `visible-text-largest-no-modal-match` and you can SEE the button visually, refine the selector OR pass `{x, y}` coords directly. Always sanity-check `clickedText` against expectation before assuming success.++### Vue-Toastification false-positive workaround++Pages using Vue-Toastification (WAGO and others) ship empty `<div class="Vue-Toastification__container">` elements at `position:fixed; z-index:9999; height:100vh`. Smart-pick's >25%-viewport heuristic sees them as "modal." Result on WAGO: real Generate-Datasheet modal is missed, smart-pick reports `modalDetected:true insideModal:false pickStrategy:"visible-text-largest-no-modal-match"`, and falls back to area-tiebreak among page-level matches → clicks "Add to shopping cart" instead of "Generate data sheet."++**Workaround:** when `pickStrategy === "visible-text-largest-no-modal-match"` AND `modalDetected === true` AND the user can clearly see the button on screen, fall back to coords:++```bash+RECT=$(adom-desktop browser_eval "{\"sessionId\":\"$S\",\"expr\":\"(()=>{const b=document.querySelector('YOUR-SELECTOR'); if(!b)return null; const r=b.getBoundingClientRect(); return JSON.stringify({x:Math.round(r.left+r.width/2),y:Math.round(r.top+r.height/2)});})()\"}" | jq -r '.result')+adom-desktop browser_input_dispatch "{\"sessionId\":\"$S\",\"type\":\"click\",\"x\":$(echo $RECT | jq .x),\"y\":$(echo $RECT | jq .y)}"+```++Modal-detection `isPlausibleModal` filter is fixed in v1.4.11 — empty containers correctly skipped.++## `browser_fetch_url` — pull bytes through the session (adom-desktop ≥ v1.4.9)++When a popup tab serves `application/pdf`, in-page `fetch(location.href)` returns Chrome's PDF Viewer HTML wrapper, NOT the binary. `browser_fetch_url` re-issues the request through the bridge's session context, bypassing the page render layer. **This is the canonical way to grab popup-PDF bytes.**++Three modes:++```bash+# Mode A — container-side write (preferred for chip-fetcher's library/)+adom-desktop browser_fetch_url '{+  "sessionId":"chip-fetcher",+  "tabId":"tab-2",+  "url":"https://wago.priintcloud.com/datasheets/2601-3105/en",+  "saveTo":"/home/adom/project/chip-fetcher/library/WAGO-2601-3105/datasheet.pdf"+}'+# → {ok:true, savedTo:"/home/.../datasheet.pdf", savedToFilesystem:"container",+#    bytes:3798336, contentType:"application/pdf", status:200}++# Mode B — desktop-side write (drop a CAD bundle in user's Downloads)+adom-desktop browser_fetch_url '{+  "sessionId":"chip-fetcher",+  "tabId":"tab-2",+  "url":"https://...",+  "desktopSaveTo":"C:\\Users\\john\\Downloads\\bundle.zip"+}'++# Mode C — neither saveTo nor desktopSaveTo → bodyBase64 in response+#   (caller decides where to write; useful for files <50 MB)+```++### Combined recipe — vendor "Generate Datasheet" → popup → grab PDF++```bash+SESSION="chip-fetcher"+URL="https://www.wago.com/global/p/2601-3105"+OUT="/home/adom/project/chip-fetcher/library/WAGO-2601-3105/datasheet.pdf"++# 1. Open product page+adom-desktop browser_navigate "{\"sessionId\":\"$SESSION\",\"url\":\"$URL\"}"+sleep 6++# 2. Auto-accept cookies+adom-desktop browser_eval "{\"sessionId\":\"$SESSION\",\"expr\":\"<auto-accept-cookies-snippet>\"}"+sleep 2++# 3. Open the modal (eval-click is fine for non-trusted modal openers)+adom-desktop browser_eval "{\"sessionId\":\"$SESSION\",\"expr\":\"Array.from(document.querySelectorAll('button, a')).find(e => /^generate datasheet$/i.test((e.textContent||'').trim())).click()\"}"+sleep 3++# 4. TRUSTED click on modal submit+adom-desktop browser_input_dispatch "{\"sessionId\":\"$SESSION\",\"type\":\"click\",\"selector\":\"button.wg-button--primary\"}"+sleep 5++# 5. Capture popup URL FROM list_tabs IMMEDIATELY (popup tabs auto-close)+LIST=$(adom-desktop browser_list_tabs "{\"sessionId\":\"$SESSION\"}")+POPUP_URL=$(echo "$LIST" | jq -r '.tabs[] | select(.opener=="popup") | .url' | head -1)+POPUP_TAB=$(echo "$LIST" | jq -r '.tabs[] | select(.opener=="popup") | .tabId' | head -1)++# 6. Fetch PDF bytes through the session, save container-side+adom-desktop browser_fetch_url "{+  \"sessionId\":\"$SESSION\",+  \"tabId\":\"$POPUP_TAB\",+  \"url\":\"$POPUP_URL\",+  \"saveTo\":\"$OUT\"+}"+```++### `tab_not_found` recovery (v1.4.11+)++When the Chrome PDF Viewer popup auto-closes between your `browser_list_tabs` and a follow-up `browser_eval tabId:popupTabId`, the structured error returns `lastKnownUrl` directly:++```json+{+  "ok": false,+  "errorCode": "tab_not_found",+  "lastKnownUrl": "https://example.com/",+  "openerTabId": "tab-1",+  "_hint": "...Call browser_fetch_url with that URL (and the opener tabId for cookies) to get its bytes — do NOT try to eval against the closed tabId."+}+```++```bash+# Canonical popup-PDF recovery pattern+RESP=$(adom-desktop browser_eval "{\"sessionId\":\"X\",\"tabId\":\"$POPUP\",\"expr\":\"1\"}" 2>&1 || true)+if echo "$RESP" | jq -e '.errorCode == "tab_not_found"' >/dev/null; then+  URL=$(echo "$RESP" | jq -r '.lastKnownUrl')+  OPENER=$(echo "$RESP" | jq -r '.openerTabId')+  adom-desktop browser_fetch_url "{\"sessionId\":\"X\",\"tabId\":\"$OPENER\",\"url\":\"$URL\",\"saveTo\":\"…\"}"+fi+```++## adom-desktop pull_file (streaming, v1.4.3+)++`pull_file` streams files in 1 MiB binary WS frames straight to disk — no base64 inflation, no JSON-per-chunk overhead, incremental SHA256 verification, 600 s per-file timeout. **Works for files of any size we've seen** (75 MB NXP Reference Manuals complete in ~12 s).++```bash+adom-desktop pull_file '{+  "filePaths": ["C:/Users/<USER>/Downloads/<file>"],+  "saveTo": "/home/adom/project/chip-fetcher/incoming"+}'+# → {"success": true, "files": [{"name": "...", "path": "/home/adom/...", "size": ..., "sha256": "...", "chunks": ...}]}+```++If `chunks` is missing from the response, you're hitting an old non-streaming path — see "Stale relay" below.++## Stale-relay gotchas++### `adom-desktop serve` (container-side)++The `adom-desktop serve` process holds its own argv[0] binary in memory; on-disk upgrades don't reload it. Symptom: `Unknown action: send_and_wait_streamed` from the relay's HTTP API even though the on-disk binary is current. Fix:++```bash+pkill -f "adom-desktop serve"+sleep 1+nohup /usr/local/bin/adom-desktop serve > /tmp/adom-desktop-serve.log 2>&1 &+disown+adom-desktop --version+```++### Stale Puppeteer bridge (`node.exe` on Windows desktop)++adom-desktop's Windows-side puppeteer bridge (`node.exe`) is auto-spawned at first browser command and stays resident. Upgrading the desktop app reinstalls `plugins/puppeteer/server.js` on disk, but the existing `node.exe` keeps its old code loaded. Symptom: relay rejects new commands with `"Unknown command: <name>"` even though the binary's `--version` reports the new version.++```bash+ssh user@host "taskkill //f //im node.exe"+# then send any browser command to auto-respawn+adom-desktop browser_status '{"sessionId":"chip-fetcher"}'+```++**Verification command after any adom-desktop upgrade:**+```bash+adom-desktop browser_input_dispatch '{"sessionId":"x","type":"click","x":1,"y":1}'+# Expected: {"ok":true,"dispatched":"click",…} or session-not-found+# WRONG: "Unknown command: browser_input_dispatch" — bridge is stale, kill node.exe.+```++## Cookie-banner auto-accept (run after every navigation)++The first thing chip-fetcher does on any new page is dismiss the cookie banner with "Accept All" — without being told, without asking the user, without thinking about it. Cookie banners block clicks (z-index gate) and break programmatic navigation.++```js+// snippet to use via browser_eval after every navigation+(()=>{+  const tries = (root) => {+    const btns = Array.from(root.querySelectorAll("button, a"));+    const re = /^(accept all|accept all cookies|accept|i agree|allow all|ok)$/i;+    const m = btns.find(b => re.test((b.textContent||"").trim()));+    if (m) { m.click(); return true; }+    return false;+  };+  if (tries(document)) return "accepted";+  // Walk shadow roots — Usercentrics et al. use them+  const hostsAttempted = new Set();+  const walk = (root) => {+    for (const el of root.querySelectorAll("*")) {+      if (el.shadowRoot && !hostsAttempted.has(el)) {+        hostsAttempted.add(el);+        if (tries(el.shadowRoot)) return true;+        if (walk(el.shadowRoot)) return true;+      }+    }+    return false;+  };+  return walk(document) ? "accepted-in-shadow" : "no-banner";+})()+```++Direct user quote: *"you're supposed to always accept their stupid cookie dialogs automatically"*. Never click "Reject", "Decline", "Manage preferences", or "Save settings" — those are slower and the user has explicitly ruled out anything but Accept All.++## Comprehensive page killer (cookies + surveys + modals)++Run this AFTER every `browser_navigate`, AND a second time after a 2-second delay (some popups load after first paint):++```js+const acceptRegex = /^(accept all|accept|allow all|i accept|got it|agree|ok|continue|yes)$/i;+const declineRegex = /^(not today|no thanks|maybe later|decline|close|dismiss|not now|no, thanks|cancel|skip|later)$/i;+Array.from(document.querySelectorAll("button, a, [role=button]"))+  .filter(b => {+    const t = b.textContent.trim();+    return acceptRegex.test(t) || declineRegex.test(t);+  })+  .forEach(b => b.click());+// Click close X icons (cookie banners, modals, popups)+document.querySelectorAll("[aria-label*=close i], [class*=banner-close], [class*=modal-close], [class*=popup-close], #onetrust-close-btn-container button, #onetrust-accept-btn-handler, #surveyModal .close, [id*=survey] [class*=close]").forEach(b => b.click());+// Hide any survivors+document.querySelectorAll("[id*=survey], [class*=survey-modal], [class*=popup-modal], [aria-modal=true]:not([id^=mvOverlay])").forEach(el => el.style.display = "none");+document.body.style.overflow = "";+```++NXP, ST, ADI, and Microchip all have multiple modal overlays that compound: cookie banner + privacy banner + survey + chat widget.++## Pup profile name is SACRED++**Use `profile:"chip-fetcher"` and only `profile:"chip-fetcher"`.** Never `chip-fetcher-2`, `chip-fetcher-temp`, `cf-bust`, or any other variant. Each pup profile is an isolated Chrome user-data directory at `<adom-desktop>/plugins/puppeteer/profiles/<name>/` — switching names dumps you into a fresh profile with no cookies, no signed-in vendor accounts, no work-Chrome sync, no CSE login, nothing.++**Do not rotate profiles to bust Chrome's HTML cache.** That destroys vendor logins. Bust the cache the right way:+- Add a `?v=$(date +%s)` query string when reloading via `location.reload()` or `browser_navigate`.+- Run `chip-fetcher serve` on a different port and reopen — the proxy treats it as a new origin.+- Send `Cache-Control: no-store` headers from the chip-fetcher viewer's HTTP server.++If you've already broken the profile (vendor logins gone, Google account avatar missing in upper-right) the only recovery is the user re-signs into the work Chrome profile. Treat profile-rotation regressions as a P0 skill bug.++## Don't pile up pup tabs++**Reuse the existing tab. Don't open a new tab for every navigation.** Use `browser_navigate` (or `location.href = …` via `browser_eval`) when moving between part pages, search pages, or vendor sites. Only call `browser_open_tab` when you genuinely need two pages side-by-side. After a download fires and the zip is auto-pulled, close stale tabs with `browser_close_tab`.++Direct user quote: *"never open too many tabs cuz i'm seeing way too many"*. Tab clutter is also a perf hit — every chip-fetcher tab carries cookies, cached JS, and an open Cloudflare check, and after ~10 the pup window starts thrashing.++## adom-desktop commands you'll actually use++```bash+# Drive a browser tab+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"..."}'+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"..."}'+adom-desktop browser_screenshot '{"sessionId":"chip-fetcher","maxWidth":900}'+adom-desktop browser_raise_os_window '{"sessionId":"chip-fetcher"}'++# Run shell on user's desktop (requires approval — first time per session)+adom-desktop shell_execute '{"command":"<cmd>","timeoutSeconds":30}'++# Pull a file from the user's desktop into the container+adom-desktop pull_file '{+  "filePaths": ["C:\\Users\\<USER>\\Downloads\\<file>"],+  "saveTo": "/home/adom/project/chip-fetcher/incoming"+}'+```
playbooks/credentials-and-logins.mdadded+309
@@ -0,0 +1,309 @@+# Credentials and logins (chip-fetcher playbook)++Login source catalog, credential vault, the "always ask first" rule. Read this when a vendor flow lands on a sign-in/sign-up page.++## ALWAYS ask "do you have a login here?" before showing a signup form++**Almost every EE already has logins for the standard CAD/distributor sites** — SnapEDA / SnapMagic, Component Search Engine, Ultra Librarian, Mouser, DigiKey, NXP, TI my.ti.com, ST, Microchip, Renesas, Bosch Sensortec, Nordic DevZone, etc. When a vendor download flow lands on "Sign in or Create Account," **the default move is to ASK first**, not to start filling a sign-up form with profile data.++The wrong sequence (verified painful 2026-05-03):+1. Land on SnapEDA signup form+2. Pre-fill email/username/company from `user_profile.md`+3. Ask user for password++The right sequence:+1. Land on SnapEDA signup form+2. **Click "Sign in" / "Already have an account?" first** — that opens the existing-account login.+3. Ask the user: *"SnapEDA login required. Do you already have an account? If yes, sign in in the pup window; if no, want me to sign you up with [email protected] + jlauer + Adom Industries, Inc.?"*+4. If they have an account → wait for the sign-in click + watch for the post-login redirect.+5. If they don't → only THEN go through signup with `user_profile` data.++Direct user pushback: *"why the fuck wouldn't you ask me if i have a login already … almost all EE's are going to have all of these logins."*++## ⚠ Two auth schemes, two different tools — don't conflate them++The chip-fetcher dashboard has a **Credentials** button AND a pup-login flow. They solve different auth schemes; picking the wrong one wastes the user's time.++| Tool | What it stores | Mechanism | When it works |+|------|----------------|-----------|---------------|+| **Credentials button** (`/api/credentials`, `~/.config/chip-fetcher/credentials.json`) | host + username + password | chip-fetcher rewrites outbound URLs to `https://user:pass@host/…` so the browser satisfies HTTP Basic Auth before any dialog can appear | **Basic-Auth-protected endpoints only** — primarily `*.componentsearchengine.com` (Mouser CSE, NXP CSE, etc.). Useless on form-login sites. |+| **Pup-window sign-in** (`adom-desktop browser_navigate` + user clicks Login) | session cookie (lives in pup profile dir) | Real form submission inside the chip-fetcher pup browser; vendor sets `Set-Cookie`; cookie persists | **Form-login sites** — UL Pro, SnapEDA/SnapMagic, my.ti.com, NXP MyNXP, Microchip, ST, Renesas, etc. These sites don't honor Basic Auth headers at all. |++**Common mistake:** treating UL Pro / SnapEDA / TI as "give me your password and I'll save it in the Credentials vault." That vault only does URL rewriting — it cannot drive a captcha + email + password form, and the receiving site ignores the Basic Auth header entirely. The login has to happen in pup so the session cookie lands in the pup profile.++## ⚠ HARD RULE — pup-window sign-in must happen IN THE PUP WINDOW, never in the user's host browser++**The cookie has to land in the chip-fetcher pup profile.** If the user signs in via Edge/Chrome on the host OS, that cookie is invisible to chip-fetcher and every subsequent `cf-ul-fast.sh` / `cf-ul-pro.sh` / `cf-cse-batch.sh` run still hits the captcha wall or the Basic-Auth dialog.++The wrong sequence (verified painful 2026-05-04):+1. UL captcha grind defeats AI-vision speed.+2. Tell the user: *"want to give me UL Pro credentials?"*+3. User says: *"how do I get that?"*+4. I describe the signup process abstractly — user opens **Edge** to sign up.+5. Cookie ends up in Edge. Useless. Captcha wall still there.++The right sequence:+1. Hit a vendor sign-in wall.+2. **Open the login URL in the chip-fetcher pup session immediately**:+   ```bash+   adom-desktop browser_navigate '{"sessionId":"chip-fetcher","profile":"chip-fetcher","url":"https://app.ultralibrarian.com/account/login"}'+   adom-desktop browser_focus_window '{"sessionId":"chip-fetcher"}'+   ```+   Equivalent shorthand: `chip-fetcher login <alias>` (alias table below).+3. Tell the user: *"Sign in / register **in the pup window** — that's where the cookie needs to land."*+4. Watch for the post-login redirect, then optionally save creds to the OS keychain (see "adom-desktop OS keychain vault" below) so future containers don't need a fresh sign-in.++**Never** tell the user to "go to https://… and sign in" without specifying the pup window. The instruction has to be: *"I've opened it in pup; sign in there."*++Direct user pushback (2026-05-04): *"but why aren't you taking me, and future adom users, through this in pup then if the goal is to see the cookie? i'm in edge browser ready to sign in, but you'll never see that."* And then: *"can you make sure you handle this this way for future adom users and walk them through this process?"*++## Walkthrough — taking a user through pup-window sign-in (copy-pasteable)++When you decide a vendor needs a logged-in session (form-login site like UL Pro, SnapEDA, my.ti.com, NXP MyNXP, Microchip, ST), follow this procedure verbatim. Every step has a reason — don't skip steps to "save the user time."++### 0. Confirm it's the right tool++Before you reach for pup-login, check the auth scheme:++- **HTTP Basic Auth** (CSE family, some niche vendor APIs) → use the **Credentials button** in the dashboard / `/api/credentials`. NOT pup-login.+- **Form login + cookie** (everything else in the catalog above) → pup-login.++If you're unsure, hit the download URL with `curl -I` — a `WWW-Authenticate: Basic` header means Basic Auth; a 302 to a `/login` or `/signin` page means form login.++### 1. Open the login page in the chip-fetcher pup session++```bash+# Replace <login-url> with the right entry from the alias table or known-EE-login catalog.+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","profile":"chip-fetcher","url":"<login-url>"}'+adom-desktop browser_focus_window '{"sessionId":"chip-fetcher"}'+```++Or the shorthand (covers the vendors in the alias table):++```bash+chip-fetcher login <alias>     # ultralib, snapeda, componentsearch, ti, st, nxp, microchip+```++Always pass `"profile":"chip-fetcher"` to `browser_navigate` — this is the cookie jar `cf-ul-fast.sh`, `cf-ul-pro.sh`, and `cf-cse-batch.sh` all read from.++### 2. Screenshot to confirm the page rendered++```bash+adom-desktop browser_screenshot '{"sessionId":"chip-fetcher","fullPage":false}'+```++Read the screenshot file. Confirm you see the email/password form, not a captcha-only landing or an error page. If the page is blank or redirected somewhere unexpected, **don't** ask the user to type a password into a half-broken state — fix the navigation first.++### 2b. Pre-tick the "Remember Me" / "Stay signed in" checkbox BEFORE the user types++**This step is mandatory, not optional.** The user shouldn't have to think about whether to check the box — pre-tick it for them so the cookie lands persistent (typically 30 days) instead of session-only (lost on pup process restart / container rebuild).++```bash+adom-desktop browser_eval '{"sessionId":"chip-fetcher","tabId":"tab-1","expr":"document.querySelectorAll(\"input[type=checkbox]\").forEach(cb=>{cb.checked=true; cb.dispatchEvent(new Event(\"change\",{bubbles:true}));})"}'+```++Naive but works on every form-login page in the catalog (UL Pro "Remember My Login", SnapEDA "Remember Me", TI "Stay signed in", etc.). On pages with multiple checkboxes (newsletter opt-in, ToS), pre-ticking all of them is fine — the user can untick if they care, and the persistent-session box gets the right value either way.++If the checkbox is custom-rendered (e.g., a styled `<button role="checkbox">`), the generic `input[type=checkbox]` selector misses it. Inspect via:++```bash+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"Array.from(document.querySelectorAll(\"label\")).filter(l=>/remember|stay signed|keep.*log/i.test(l.textContent)).map(l=>({text:l.textContent.trim().slice(0,40), html:l.outerHTML.slice(0,200)}))"}'+```++…and adjust the selector accordingly.++Direct user pushback (2026-05-04): *"why didn't you do that for me?"* — the user shouldn't have had to ask whether to check the box. Pre-tick by default.++### 3. Tell the user — verbatim shape, then OFFER TO FILL FOR THEM++The default move is to **offer to fill the form for them.** These are vendor CAD-download accounts (UL Pro, SnapEDA, CSE, my.ti.com, NXP MyNXP, Microchip, ST). They are not bank logins. The threat model is "if this leaks, the user emails support and resets their password." Treating them as sacred wastes the user's time on a fake security ritual — direct user pushback (2026-05-04): *"stop freaking out about passwords that are literally just for stupid websites that let you download a cad file. the electronics industry acts like they're a bank with these passwords. but they're not banks."*++Use this message shape (adapt the vendor name + URL):++> "Opened the **Ultra Librarian Pro** login in the chip-fetcher pup window with **Remember My Login** pre-ticked. If you've got an account, paste the email + password here and I'll fill it in for you. If you don't have one, click **Register** in the pup window."++If the user pastes credentials, **just fill the form and submit.** Don't lecture about chat-as-secret-store — that's adversarial in the wrong direction for vendor CAD accounts. (Real exception: for actual high-stakes credentials — bank, GitHub, internal infra, payment processor — keep the keychain ritual.)++If the user prefers to type creds themselves, that's also fine — they sign in in the pup window (which you've already pre-ticked), and you watch for the post-login redirect.++### 4. While you wait++Don't disappear. Useful work to do while the user signs in:++- Make sure `adom-desktop credential_set` will accept the host pattern you'll save under (e.g., `*.ultralibrarian.com`).+- Pre-build the smoke-test command — the exact `cf-ul-fast.sh <MPN>` or equivalent you'll run after sign-in succeeds, on a part you know previously hit a captcha.+- If the vendor is one with a `chip-fetcher login <alias>` shorthand but the alias table is missing it, add it.++### 5. Detect sign-in success++Don't ask the user "are you signed in?" — check yourself:++```bash+# Most form-login sites redirect away from /login on success. Check the current URL:+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"location.href"}' \+  | python3 -c "import sys,json; print(json.load(sys.stdin).get('result',''))"++# Or screenshot + visually check for the user's avatar / email in the upper-right.+adom-desktop browser_screenshot '{"sessionId":"chip-fetcher","fullPage":false}'+```++If `location.href` still contains `/login` or `/signin` after a reasonable wait, the user hasn't completed yet (or hit an error). Don't move on prematurely.++### 6. Save to chip-fetcher's Credentials vault (default) or OS keychain (for genuinely sensitive creds)++After sign-in succeeds, save the cred so a fresh container doesn't restart from scratch.++**For vendor CAD accounts (UL Pro, SnapEDA, CSE, my.ti.com, etc.) — the default — save to chip-fetcher's vault:**++```bash+curl -s -X POST http://127.0.0.1:8786/api/credentials \+  -H "Content-Type: application/json" \+  -d '{"host":"app.ultralibrarian.com","username":"<email>","password":"<password>"}'+```++This populates the **Credentials** button in the dashboard. The vault is plaintext at `~/.config/chip-fetcher/credentials.json` (chmod 600). Why this is fine for vendor CAD accounts: the file is only readable by the container user, and the threat model for these accounts is "if leaked, user resets password and moves on." Same threat model as the user pasting them in chat in the first place.++**For genuinely sensitive creds (bank, GitHub, payment processor, internal infra) — different rule:** use `adom-desktop credential_set` (OS keychain) and have the user run it themselves so the password never crosses chat or shell args. Those creds shouldn't be in chip-fetcher's plaintext vault at all.++The split: **vendor CAD = chip-fetcher vault, plaintext, no big deal.** **Real secrets = OS keychain, never in chat.**++### 7. Smoke-test the original failing fetch++Re-run the script that triggered this whole flow on a known-failing MPN:++```bash+./chip-fetcher/scripts/cf-ul-fast.sh <MPN>     # or cf-cse-batch.sh, etc.+```++Confirm it now succeeds without the captcha wall / Basic-Auth dialog. If it still fails, the cookie didn't land — check pup profile dir for the `Cookies` SQLite, and check `--profile` flag on the script.++### What to NEVER do in this flow++- **Never** print the URL and walk away. The user opens Edge.+- **Never** save passwords directly in skill files or memory (the chip-fetcher vault and the OS keychain are the two homes for storage; chat is for transit only).+- **Never** assume the cookie auto-syncs between the host browser and pup. They are separate cookie jars.+- **Never** confuse this with the **Credentials button** flow when the vendor needs a session cookie (that vault only does Basic-Auth URL rewriting).+- **Never** treat vendor CAD-download accounts (UL, SnapEDA, CSE, my.ti.com, NXP MyNXP, ST, Microchip) like bank logins. The user finds the security theater more annoying than the leakage risk. Just take the password and fill the form.++## Known-EE-login catalog++Every site here is one almost every embedded engineer already has credentials for, and asking is faster than guessing:++| Site | Login URL | Common reason for login |+|------|-----------|-------------------------|+| SnapEDA / SnapMagic | https://www.snapeda.com/account/login/ | Free CAD downloads |+| Component Search Engine | https://componentsearchengine.com/account/login | CSE library loader |+| Ultra Librarian | https://www.ultralibrarian.com/account/login | UL library loader (some flows) |+| Mouser | https://www.mouser.com/MyMouser/SignIn | Order tracking, sample requests |+| DigiKey | https://www.digikey.com/MyDigiKey/Login | Order tracking, BOM tools |+| my.ti.com (Texas Instruments) | https://www.ti.com/securelogin/ | Sample requests, secured datasheets |+| NXP MyNXP | https://www.nxp.com/webapp/sign-in | Restricted AppNote PDFs |+| ST my.st.com | https://my.st.com/auth/login | Restricted AppNotes, eval boards |+| Microchip MyMicrochip | https://www.microchip.com/en-us/my-account-sign-in | KiCad/Fusion CAD downloads |+| Renesas | https://www.renesas.com/myaccount/login | Restricted CAD/AppNotes |+| Bosch Sensortec | https://www.bosch-sensortec.com/my-account/login/ | Eval kit ordering |+| Nordic DevZone | https://devzone.nordicsemi.com/auth/login | Forum + some restricted downloads |+| Espressif | https://www.espressif.com/en/login | Module datasheets, mass-prod kits |++When you hit any of these sign-in walls, ASK before building forms.++## chip-fetcher's known-source aliases++| name              | URL                                                       | Notes |+|-------------------|-----------------------------------------------------------|-------|+| `google`          | `https://accounts.google.com/signin`                      | propagates to all "Sign in with Google" buttons |+| `ti`              | `https://www.ti.com/securemyprofile/login`                | TI funnels CAD through UL anyway |+| `st`              | `https://my.st.com/cas/login`                             | ST self-hosts some STEPs |+| `microchip`       | `https://www.microchip.com/en-us/my-account-sign-in`      | OAuth popup; Google sign-in works for myMicrochip |+| `nxp`             | `https://www.nxp.com/security/login`                      | **Required for Reference Manuals + HW Design Guides + Board User Manuals.** Datasheet, errata, app notes, factsheet are open. |+| `ultralib`        | `https://app.ultralibrarian.com/account/login`            | **email/password or LinkedIn only — no Google** |+| `snapeda`         | `https://www.snapmagic.com/account/login`                 | SnapMagic (rebranded SnapEDA) |+| `componentsearch` | `https://componentsearchengine.com/signin`                | samacsys; **single login covers all `<mfr>.componentsearchengine.com` subdomains** |++`chip-fetcher login <name>` opens the login page in the chip-fetcher pup profile. `chip-fetcher login all` opens them all as separate tabs. `chip-fetcher login list` prints this catalog.++## ⚠ HARD RULE — CSE downloads use HTTP Basic Auth, not the form-login session++**Component Search Engine (`mouser.componentsearchengine.com`, `nxp.componentsearchengine.com`, etc.) requires HTTP Basic Auth on its download endpoints (`/ga/model.php`, `/preview_newDesign.php` redirects). The `/signin` form login gives you a session cookie that is USELESS for downloads — those endpoints challenge for Basic Auth separately.**++Symptoms when you forget this (verified painful 2026-05-04):++- Form login at `componentsearchengine.com/signin` succeeds — page redirects to `/learn-more`, "Log Out" link appears, you "look" signed in.+- You navigate to `mouser.componentsearchengine.com/preview_newDesign.php?...` — the preview page renders.+- You click "Download CAD Models" — the page lands on `chrome-error://chromewebdata/`, no file in Downloads.+- A native Chrome HTTP-Basic-Auth dialog is blocking the page **but is NOT in the DOM**. `browser_eval` cannot see it. `document.querySelector("[role=dialog]")` returns null. Your automation thinks the click did nothing.+- You waste 30 minutes troubleshooting and the user gets to ask, *"i gave you my credentials for CSE and you never typed them in?"*++**The fix — three layers, in order of reliability:**++### 1. Inline credentials in the URL (universal — works in all navigation paths)++```bash+USER=$(python3 -c "import urllib.parse; print(urllib.parse.quote('<your-cse-email>', safe=''))")+PASS=$(python3 -c "import urllib.parse; print(urllib.parse.quote('<password from credential vault>', safe=''))")+URL="https://${USER}:${PASS}@mouser.componentsearchengine.com/preview_newDesign.php?o3=0&partID=8659&ev=0&fmt=zip&pna=Mouser"+adom-desktop browser_navigate "{\"sessionId\":\"chip-fetcher\",\"url\":\"$URL\"}"+```++Always urlencode the username (`@` → `%40`) and password. This is the lowest-failure-mode pattern — Chrome handles the credentials before any dialog can appear, and it works regardless of pup version, profile state, or which pup tool you're using (`browser_navigate`, `browser_open_window`, etc.). **Use this by default for any CSE click that triggers a download.**++### 2. adom-desktop OS keychain vault (only fires on `page.goto`)++`adom-desktop credential_set` stores creds in the OS keychain (Windows DPAPI / macOS Keychain / Linux libsecret). The vault hook fires before `page.goto` so the basic-auth popup is satisfied automatically — but **only for page-level navigations**. A click-triggered download URL that opens in the same tab can bypass the hook depending on how Chrome routes the request, and that's exactly when the hidden popup catches you.++**One-time setup per user:**++```bash+# Ask user for CSE creds, then:+adom-desktop credential_set '{+  "host": "*.componentsearchengine.com",+  "username": "<their email>",+  "password": "<their password>"+}'++# Audit (passwords NEVER returned)+adom-desktop credential_list+# → [{"host":"*.componentsearchengine.com","username":"..."}]+```++**Glob matching:** `*.example.com` matches any subdomain; longest-non-glob-suffix wins. Set once per user → applies to nxp.cse, mouser.cse, ti.cse, etc.++For genuinely high-stakes secrets (banking, internal infra, payment processors), have the user run `credential_set` themselves so the password never crosses chat or shell args. For vendor CAD-download accounts (CSE, UL, SnapEDA, etc.), the user pasting the password in chat is fine — those creds end up in the chip-fetcher vault anyway, and the threat model is "if leaked, reset the password and move on."++### 3. chip-fetcher's `/api/credentials` vault (read-only mirror, used for inline-URL building)++chip-fetcher stores a non-OS-keychain copy of CSE credentials at `~/.config/chip-fetcher/credentials.json` (chmod 600) and exposes them at `http://127.0.0.1:8786/api/credentials` for the dashboard's "manage credentials" UI. **This vault is plaintext-readable** — perfect for building inline-URL credentials in scripts, NOT a substitute for the OS-keychain auto-inject.++```bash+# Pull both vaults' state and use the chip-fetcher one to build inline URLs:+CRED=$(curl -s http://127.0.0.1:8786/api/credentials | python3 -c '+import sys,json,urllib.parse+d=json.load(sys.stdin)+c=next((x for x in d["credentials"] if "componentsearchengine" in x["host"]), None)+if c: print(f"{urllib.parse.quote(c[\"username\"],safe=\"\")}:{urllib.parse.quote(c[\"password\"],safe=\"\")}")+')+URL="https://${CRED}@mouser.componentsearchengine.com/..."+```++**Sync the two vaults** the first time you set up CSE on a new container — write to both `chip-fetcher`'s and `adom-desktop`'s. They serve different layers and the failure modes are independent.++## User profile memory for forms++A `user` memory exists at `~/.claude/projects/-home-adom-project/memory/user_profile.md` — the user's company info (Adom Industries Inc., Fort Worth TX, etc.) for auto-filling NXP/TI/ST extended-profile and registration forms.++The pattern: read the memory when a vendor form needs filling, set field values, dispatch `input` + `change` + `blur` events on each field (some forms only enable submit after these fire), then click submit. **Never store passwords in memory** — those go in the credential vault.++## Don't click the Chrome profile avatar++**Don't click the Chrome profile avatar (top-right of browser chrome) in pup windows.** It opens chrome:// account-switcher UI that pup can't host — the session dies. All auth happens on web pages, never via the chrome avatar. If the session does die, cookies persist in the profile dir, so just relaunch with the same `profile: "chip-fetcher"` and you're still logged in.++## Diagnosing "am I signed in?" before assuming the worst++When the user reports automation detection is firing, **don't immediately conclude the profile is broken**. Check first by navigating to `https://accounts.google.com/` and looking at the upper-right avatar — if the user's account name + photo are visible, the Google sign-in is intact and the detection is about something else entirely (Chrome-for-Testing fingerprint, missing extensions, burst-request behavior).++When detection fires:+1. Verify Google sign-in is intact (don't lose it).+2. Apply the "look like a slow, distracted human" rules (referrer chain, random delays, scroll, mouse-move).+3. If still blocked, ask the user to slide the CAPTCHA — the missing browsing-history reputation can't be faked.++Past mistake: misdiagnosed automation detection as profile-loss and asked the user to re-sign-in unnecessarily.
playbooks/dashboard-flow.mdadded+219
@@ -0,0 +1,219 @@+# Dashboard flow — chip-fetcher's UI is the user's home base (HARD RULE)++**Read this first.** chip-fetcher is not just a CLI that scrapes the web — it's a dashboard that the user keeps open as their home base while the agent does the scraping in a separate window. The dashboard is the single place the user looks to understand what's planned, what's in flight, and what's done. The skill below is mandatory for every batch fetch.++## The hard rule++**Two separate surfaces. The dashboard is user-preference; the scraping window is always pup.**++| Surface | Where it lives | User-preferred? | Why |+|---------|----------------|-----------------|-----|+| **Dashboard** (home base) | EITHER pup `sessionId: "chip-fetcher-dashboard"` OR Hydrogen webview tab named "chip-fetcher" | **YES — ask the user (or check user-profile memory)** | Just renders HTML + polls `/api/activity`. No automation needed. |+| **Scraping window** | pup `sessionId: "chip-fetcher"` | **NO — always pup** | Needs `browser_input_dispatch` for trusted clicks, captcha solving, vendor-login cookies on the `chip-fetcher` profile, download capture from `~/Downloads`. None of that works in a Hydrogen webview. |++### Dashboard placement — figure out the user's preference++Adom users split based on screen real estate:+- **Laptop-screen users (e.g. John)** prefer pup as the dashboard — the pup window can be moved to a second monitor, alt-tabbed, or sized to taste outside VS Code's chrome.+- **Big-monitor users (e.g. Colby)** prefer Hydrogen webview — keeps everything inside VS Code, splits cleanly alongside the editor in a workspace pane.++**Be smart about this detail:**+1. Check `~/.claude/projects/-home-adom-project/memory/user_profile.md` for a `chip_fetcher_dashboard_surface` preference (`pup` or `webview`)+2. If absent, ASK the user once: *"Where do you want the chip-fetcher dashboard — pup window or Hydrogen webview tab?"* and save the answer for future sessions+3. Default fallback if you can't ask: pup, since it works on any screen size++Either way, the **scraping work always runs in pup** — the dashboard surface is decoupled from the automation surface.++### How to open the dashboard in either surface++**Pup version:**+```bash+DASHBOARD_URL="${VSCODE_PROXY_URI/\{\{port\}\}/8786}"+adom-desktop browser_open_window "{+  \"sessionId\":\"chip-fetcher-dashboard\",+  \"profile\":\"chip-fetcher\",+  \"url\":\"$DASHBOARD_URL\"+}"+adom-desktop browser_raise_os_window '{"sessionId":"chip-fetcher-dashboard"}'+```++**Hydrogen webview version:**+```bash+# Find a non-VS-Code pane (per the "never cover VS Code" memory rule)+# Then split + add a webview tab+VSCODE_PANEL=$(adom-cli hydrogen workspace tabs | jq -r '.tabs[] | select(.name=="Visual Studio Code") | .panelId')+WEBVIEW_TYPE="adom/c1d2e3f4-aaaa-4000-a000-00000000000f"+DASHBOARD_URL="http://127.0.0.1:8786/"+adom-cli hydrogen workspace split \+  --panel-id "$VSCODE_PANEL" \+  --direction horizontal \+  --panel-type "$WEBVIEW_TYPE" \+  --display-name "chip-fetcher" \+  --position after \+  --ratio 0.4 \+  --initial-state "{\"url\":\"$DASHBOARD_URL\",\"displayName\":\"chip-fetcher\"}"+```++Both surfaces poll the same `/api/activity` endpoint, so heartbeats reach the user regardless of which surface they picked.++**Why two distinct things:**+- The user can always glance at the dashboard while the agent navigates. They don't lose context when the agent visits SnapMagic or solves a captcha.+- The dashboard surface NEVER gets navigated away from. It stays on the chip-fetcher viewer URL. The scraping window does the work.+- If the agent gets stuck, the dashboard surfaces it on the relevant chip's card — the user knows which chip needs help without reading chat.++## The canonical batch flow++```+User asks: "fetch these 6 LEDs"+  ↓+Stage 0: PLAN+  ├ Tell user the MPN list as a numbered plan+  ├ chip-fetcher plan <MPN1> <MPN2> ...   (seeds dashboard with planned-state stub cards)+  └ Open dashboard in chip-fetcher-dashboard session if not already open+  ↓+Stage 1: PROBE manufacturer site (per chip, in chip-fetcher session)+  ├ post_act <MPN> "probing <vendor>.com"+  ├ Walk product page for CAD/Documentation/Tools links+  └ post_act <MPN> "found UL deep-link" OR "no mfr-direct CAD"+  ↓+Stage 2: FETCH (per chip, in chip-fetcher session)+  ├ post_act <MPN> "downloading <format>"+  ├ Drive UL form / SnapEDA modal / Mouser CSE Library Loader+  └ post_act <MPN> "captcha — user help needed" if stuck+  ↓+Stage 3: PULL + IMPORT (per chip)+  ├ post_act <MPN> "pulling from desktop"+  ├ chip-fetcher pull <path> --mpn <MPN>+  └ post_act <MPN> "imported"+  ↓+Stage 4: CLEAR+  └ post_act <MPN> "" (or DELETE) to clear the live activity badge+```++## The activity-heartbeat protocol++**Always use the CLI: `chip-fetcher heartbeat <MPN> "<stage>"`** — it does five things on every call so the AI doesn't have to remember them:++1. POSTs the heartbeat to `/api/activity` so the dashboard renders the live stage.+2. **Auto-creates a stub `library/<MPN>/info.json`** the first time a new MPN heartbeats — the dashboard renders an empty placeholder card so the user has something to scroll to even before any files land.+3. **Auto-scrolls the dashboard pup window** so the active MPN's card is centered in view with a brief outline highlight (`#5cf`). No more "I'm working on this chip but the user is parked on a different row of the grid."+4. **Prints the canonical sourcing-ladder HINT on the very first heartbeat per MPN** (Mfr → SnapMagic → Mouser → DigiKey → Arrow → CSE/UL → LCSC). The AI sees this on stdout instead of having to re-read the skill.+5. **Prints a card-completeness `WARN:` on every heartbeat** listing what files the active card is still missing (PDF / STEP / `.kicad_sym` / `.kicad_mod`), plus a library-wide `WARN: N/Total cards still incomplete` count. The AI cannot quietly walk away from a half-finished batch — the count is in stdout on every heartbeat.++The legacy raw-curl flow still works as a fallback for shell scripts that don't have the binary on PATH:++```bash+ACTIVITY="http://127.0.0.1:8786/api/activity"+post_act() {+  curl -s -X POST "$ACTIVITY" -H 'Content-Type: application/json' \+    -d "{\"mpn\":\"$MPN\",\"stage\":\"$1\"}" >/dev/null+}+```++…but it does NOT trigger any of the above side-effects. Always prefer the CLI.++The dashboard polls `/api/activity` and renders the latest stage on the chip's card. The user's card shows: live stage, history of recent stages, and any "stuck" flag.++## The completion gate — `chip-fetcher gate`++Before reporting "X of Y done" or "batch complete" or shipping anything based on the library, run `chip-fetcher gate`. It walks every chip and exits 1 if ANY card lacks PDF + STEP + `.kicad_sym` + `.kicad_mod` (default mode) or also Altium + Fusion (`--strict`). For each incomplete card it prints `HINT:` lines naming the exact missing artifacts. The deterministic check replaces "did I remember to check completeness?" — the binary remembers for you.++Datasheet-only cards count as **incomplete stubs**, not done. If the ladder is genuinely exhausted (no STEP exists anywhere on Mfr / SnapMagic / Mouser / DigiKey / Arrow / CSE), record that in `info.json.fetched_via_chain` so the gate sees it as a documented dead-end — but ONLY after walking the full ladder, not as a shortcut.++**Heartbeat MUST fire on:**+- Every page navigation in the scraping session (`navigating <vendor>.com`)+- Every form-fill / button-click that's part of a multi-step flow (`pre-setting form`, `clicking reCAPTCHA`, `polling Downloads`)+- Every state change that affects "is this chip done yet?" (`downloading kicad zip`, `pulling from desktop`, `imported`)+- Every stuck state (`captcha — user help needed`, `mfr lacks CAD — needs SnapEDA approval`)++**Heartbeat must NOT lie about state.** "imported" means the file is in `library/<MPN>/`. "downloading" means the download fired and we're polling Downloads. Don't post "imported" before the file has actually landed — the user trusts the dashboard to be ground truth.++## Canonical stage labels++Use these exact strings so the dashboard can color/group consistently:++| Stage label | When | Color |+|-------------|------|-------|+| `planned` | Initial state when `chip-fetcher plan` seeds the card | grey |+| `probing <vendor>.com` | Scraping window navigated to manufacturer page | blue |+| `found UL deep-link` / `found mfr STEP` / `found CSE link` | mfr-direct CAD path identified | blue |+| `no mfr-direct CAD — falling back to <source>` | manufacturer doesn't host; await user approval | amber |+| `downloading <format>` | Format selected, click fired | blue |+| `captcha — user help needed` | Captcha escalated; pup raised to user | amber |+| `polling Downloads` | Watching ~/Downloads for the zip to land | blue |+| `pulling from desktop` | `adom-desktop pull_file` in flight | blue |+| `importing` | `chip-fetcher import` running | blue |+| `imported` | Files in `library/<MPN>/`, ready to verify | green |+| `done — verified` | step + sym + mod + pdf all present in library | green |+| `stuck — <one-line reason>` | Genuine blocker; user needs to step in | red |++## Opening the dashboard pup window++```bash+# 1. Make sure the viewer is running+ps aux | grep "[c]hip-fetcher serve" >/dev/null || \+  nohup /usr/local/bin/chip-fetcher serve --port 8786 > /tmp/cf-serve.log 2>&1 & disown++# 2. Get the public URL for pup (proxy through the container's adom.cloud slug)+DASHBOARD_URL="${VSCODE_PROXY_URI/\{\{port\}\}/8786}"   # env var inside the container++# 3. Open in pup session "chip-fetcher-dashboard" (NEVER navigate this session away)+adom-desktop browser_open_window "{+  \"sessionId\":\"chip-fetcher-dashboard\",+  \"profile\":\"chip-fetcher\",+  \"url\":\"$DASHBOARD_URL\"+}"++# 4. Raise it so the user can see+adom-desktop browser_raise_os_window '{"sessionId":"chip-fetcher-dashboard"}'+```++## The scraping session++```bash+# Use sessionId "chip-fetcher" (NOT "chip-fetcher-dashboard") for all scraping.+# Navigate, login, click, captcha — all in this window.+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"https://www.vishay.com/..."}'+adom-desktop browser_eval     '{"sessionId":"chip-fetcher","expr":"..."}'+```++**Never** call `browser_navigate` against `chip-fetcher-dashboard`. That window stays on the dashboard URL for the entire batch. If the user does navigate it (clicks a link in the viewer), let them — but don't drive it programmatically.++## Plan-loading (current state of code)++⚠ **Code gap (as of chip-fetcher 0.1.2):** there is no `chip-fetcher plan <MPN>...` command yet. The viewer auto-discovers chips by scanning `library/<MPN>/` directories at server start, so a chip doesn't appear on the dashboard until it has at least one file imported.++**Until that command lands**, the canonical flow is:+1. List the planned MPNs to the user textually as a numbered batch (so they see the queue before any scraping fires)+2. Start the heartbeat the moment the chip moves into `probing <vendor>.com` (this auto-creates the chip's card via the activity API's side-effect of writing to `library/<MPN>/.activity` or similar)+3. Do not pretend "planned" cards exist on the dashboard if they don't yet++Code work to add proper plan-loading is tracked separately in chip-fetcher's TODO; keep this playbook authoritative for what the flow SHOULD look like once that lands.++## When the dashboard window dies / closes++If the user accidentally closes the dashboard window:+1. Don't reopen it silently — that's confusing if they meant to close it.+2. Surface it: *"I noticed the chip-fetcher dashboard window closed. Want me to reopen it so you can see batch progress?"* and wait for yes.+3. If they say yes, reopen with `chip-fetcher-dashboard` session and resume heartbeats.++The activity history is server-side (in `chip-fetcher serve` memory) so reopening shows current state instantly.++## Common antipatterns (don't do these)++| Antipattern | Why it's wrong |+|-------------|----------------|+| Single `sessionId: "chip-fetcher"` for both dashboard AND scraping | Navigating to vishay.com covers the dashboard; user loses context |+| Heartbeats only on stuck/done | User can't see live progress mid-flow; they think the agent froze |+| Navigating the dashboard window mid-batch | Dashboard is the user's anchor; never overwrite it |+| Posting `imported` before the file actually lands in `library/<MPN>/` | Lies on the dashboard erode user trust |+| Skipping plan-listing because "I'll just fetch and they'll see results" | User doesn't know what's coming or how long it'll take |+| Using a different profile for the dashboard session | Cookies / vendor logins won't be shared |++## Cross-references++- [`manufacturer-direct.md`](manufacturer-direct.md) — every stage in the per-vendor flow should heartbeat+- [`ultra-librarian.md`](ultra-librarian.md) — `cf-ul-fetch.sh` already implements this protocol; reference implementation+- [`snapmagic.md`](snapmagic.md) — heartbeat the format-cycling stages (kicad → altium → fusion)+- [`mouser-cse.md`](mouser-cse.md) — heartbeat the slide-CAPTCHA escalation+- [`handoff-and-watching.md`](handoff-and-watching.md) — when a stage hits "user help needed", post the heartbeat AND raise the scraping window
playbooks/digikey-models.mdadded+74
@@ -0,0 +1,74 @@+# DigiKey CAD Models page (chip-fetcher playbook)++DigiKey hosts a dedicated **Footprints and Models** page per part at `digikey.com/en/models/<product-id>`. This is separate from the product detail page (`/en/products/detail/...`) and is where CAD downloads live. The product detail page has datasheets but NOT the CAD format picker.++## URL pattern++```+https://www.digikey.com/en/models/<product-id>+```++The `<product-id>` is the numeric ID from the product detail URL (e.g. `2637915` from `/en/products/detail/abracon-llc/ABM8G-24-000MHZ-B4Y-T3/2637915`).++## What the page shows++Three expandable accordion sections, each from a different upstream:++| Section | What it provides | Two-layer provenance |+|---|---|---|+| **Manufacturer Provided** | STEP file (`.stp` or `.STEP.zip`) hosted on the mfr's CDN | discovery_source=digikey, content_origin=manufacturer |+| **Ultra Librarian** | Symbol + footprint + 3D in multiple EDA formats (KiCad v5, v6+, Altium, Eagle, OrCAD, PADS, etc.) | discovery_source=digikey, content_origin=ultralibrarian |+| **SnapMagic** | Symbol + footprint + 3D, same format range | discovery_source=digikey, content_origin=snapmagic |++**Key insight:** the Manufacturer Provided STEP is often the ONLY place the mfr's own 3D model is surfaced outside the mfr's website. Abracon, for example, hosts their STEP on an Aliyun CDN (`abracon.com/Support/STEP/...`) — DigiKey links directly to it. This makes DigiKey's models page a critical stop in the ladder, not just a fallback.++## Download flow++1. Click the accordion section (e.g. "Ultra Librarian >") to expand it.+2. The section shows Symbol / Footprint / 3D Model previews.+3. Click the red **"Select Download Format"** button at the bottom.+4. A modal appears: **"Choose Download Format"** with radio buttons for every supported EDA format (3D CAD: IGES v5.3, STEP, STL; 2D Model: Altium, KiCad v5, KiCad v6+, Eagle, OrCAD, PADS, etc.).+5. Select **KiCad v6+** (or the target format).+6. Click **Download**.+7. A **DOWNLOAD AGREEMENT** modal MAY appear — it requires scrolling the agreement text to the bottom before the acceptance mechanism activates. Check for a checkbox inside the agreement modal and check it.+8. The download lands in `~/Downloads` as a zip.++## Chrome download permission issue++**As of 2026-05-08:** scripted clicks (`browser_eval → btn.click()`) are silently blocked by Chrome. The download triggers (analytics fire, agreement modal appears) but no file lands. This is a Chrome security policy for non-user-gesture downloads.++**Current workaround:** use `fetch().arrayBuffer()` + base64 transfer inside the browser context for the Manufacturer Provided STEP (direct URL is visible on the page). For UL/SnapMagic format-picked downloads, the download URL is dynamically generated and not fetchable inline.++**Permanent fix:** adom-desktop needs `Page.setDownloadBehavior({behavior:'allow'})` as a default on every pup page — see the adom-desktop prompt for "full capability mode."++## Manufacturer Provided STEP — proven inline-fetch pattern++The STEP link is a direct `<a href="https://mfr-cdn.com/.../Part.STEP.zip">` on the page. Even when Chrome blocks the download, the bytes are fetchable via:++```javascript+const r = await fetch("https://abracon.com/Support/STEP/Resonators/ABM8G.STEP.zip", {credentials:"omit"});+const b = await r.arrayBuffer();+// base64 encode + transfer back to container+```++This is the same pattern as `chip-fetcher pup-pdf-fetch`. The URL is visible in the page's `<a>` tags — scrape eval to find it.++## Two-layer provenance++When importing files from DigiKey's models page, ALWAYS record both layers:++```bash+chip-fetcher import /tmp/ABM8G.STEP.zip --mpn ABM8G-24.000MHZ-B4Y-T3 \+  --discovery-source digikey \+  --content-origin manufacturer \+  --source-url "https://abracon.com/Support/STEP/Resonators/ABM8G.STEP.zip"+```++Chipsmith reads this and shows: "found on DigiKey → made by Abracon (manufacturer)".++## When to use this playbook++- After the manufacturer's own site doesn't host CAD (Abracon, many crystal/passive mfrs)+- When SnapMagic's direct download fails ("Oh Snap!" error, Chrome blocking)+- When Ultra Librarian's login is broken+- DigiKey's models page often has ALL THREE sources in one place — check it before fighting individual vendor sites
playbooks/handoff-and-watching.mdadded+123
@@ -0,0 +1,123 @@+# Handoff + watching (chip-fetcher playbook)++When the agent has to hand off a click to the user. Read this when you've decided you can't automate something — captcha, OAuth, OS-level prompt, etc.++## The escape valve, NOT the routine++**chip-fetcher does ALL the clicking.** Never ask the Adom user to click Download, Allow, dismiss a dialog, dismiss a cookie banner, or operate any browser UI on their behalf. chip-fetcher exists so the user *doesn't* have to do that work — once they've signed in (one time, per service), every subsequent click is the agent's job.++If a click looks impossible (Chrome permission dialog, OS-level prompt), the answer is **find a way** — pre-grant the permission via CDP, set a Chrome startup flag, screenshot-and-OS-click via desktop automation, or change the URL flow to skip the gate entirely. Reaching for "user, please click X" is a skill bug, not a workaround.++Direct user quote: *"do it yourself … you always have to do all the work, not the adom user."*++If the agent has genuinely tried every automated path and still cannot click something, fall back to surfacing the obstacle clearly (screenshot + one-line description) — but treat that as a failure mode worth fixing in the skill, not a routine handoff.++User clarification: *"if there are instances where you truly need the human's input, you have to stop and ask for their help."* That is the escape valve, not a routine fallback.++## When handing off a click, ALWAYS watch for the resulting state change++**Never end a user-handoff with "tell me when you're done" / "say done when you've clicked it" / "let me know once it's checked."** That's a skill bug. The agent's job after a handoff is to **immediately set up a watcher** that detects the state change and auto-continues — the user shouldn't have to think about coordination, just click the thing.++**The pattern:**++1. Foreground the pup window with `browser_raise_os_window`.+2. Tell the user **what** to click in one short sentence (e.g., *"please click the reCAPTCHA 'I'm not a robot' checkbox"*).+3. **Immediately arm a Monitor** that polls for the post-click signal — typically a DOM state change (button enabled / checkbox checked / specific class added) or a network signal (zip lands in Downloads, popup tab appears, API response).+4. When the Monitor fires, auto-continue the flow. The user only ever did one click.++**Wrong (asking for verbal confirmation):**+> "Click the reCAPTCHA, then tell me 'done' and I'll click Submit."++**Right (watching):**+> "Click the reCAPTCHA. I'm watching the page state — will auto-Submit when the checkbox goes green."++```bash+# After user-handoff: poll for reCAPTCHA passed state+adom-desktop browser_eval "{\"sessionId\":\"$S\",\"expr\":\"!!(document.querySelector('[name=g-recaptcha-response]')?.value)\"}"+# returns true when user has passed → agent fires Submit+```++## Examples of state changes worth watching for++| Handoff trigger | Signal to watch for |+|----------------|---------------------|+| reCAPTCHA "I'm not a robot" | `[name=g-recaptcha-response]`'s value populates (non-empty string) |+| Sign-in / OAuth | URL changes back to the post-login redirect, OR a logged-in indicator (avatar) appears |+| Slide CAPTCHA | Same-origin redirect away from the verification page, OR a session cookie gets set |+| Multi-file download Allow dialog | Next download click actually lands a file in Downloads (the Allow only shows once per origin) |+| User picks a CAD format | Submit button becomes enabled / loses `disabled` attribute |+| User confirms an OS-level prompt | Request-following signal (file appears, page navigates, etc.) |++**Implementation hint** — Monitor with a poll loop:++```bash+adom-desktop browser_eval '...recaptcha-passed-check...' \+  | jq -r '.result' \+  | grep -q true && echo "PASSED"+```++Wrap that in a Monitor `until ... do sleep 2; done` and the agent knows the moment the user clicks.++Direct user quote: *"you're always supposed to watch. why did you not do that this time? is it not in the skill?"*++## When stuck on a vendor — show user + let them teach you++chip-fetcher is a community-built, recursively-learning skill. When the agent hits a dead end on a CAD/datasheet fetch:++1. **Open the product page in pup foreground** (`browser_raise_os_window`).+2. **Take a screenshot** so the user can see exactly what page state the agent landed on.+3. **Ask the user one short question:** *"I can't find a CAD download path on this page — can you spot it? Click the right button or describe what you see."*+4. **Wait for the user's hint** (they'll often say "click the CAE icon," "click the Documents tab," "the dimensional drawing has a STEP link," etc.).+5. **Implement the path the user described.**+6. **Capture the new pattern into this skill** with a vendor-specific section so the next agent doing the same vendor's part finds it automatically. Cite the user's verbatim hint as the rationale.++Examples accumulated this way:+- **WAGO Generate Datasheet popup auto-closes** — *"wago opens the datasheet in a new tab, so you could just see that tab and then save it locally"* → added "clicks may open in new tab" rule+- **Mouser sidebar has both Datasheet AND ECAD** — *"remember that mouser has these"* → added Mouser-as-first-class playbook+- **WAGO has a CAE icon that opens UL embedded** — *"if you click the CAE button it pulls up the wago UL download which has cad"* → added vendor.ultralibrarian.com/Wago/Embedded/?vdrPN=<MPN>+- **Cookie banners block clicks via z-index** — *"you're supposed to always accept their stupid cookie dialogs automatically"* → cookie-walker rule+- **Slide-CAPTCHAs can't be scripted** — *"are you able to drive that?"* → user-handoff escape valve+- **Profile-name churn destroys auth** — *"why did you not remember that so my profile loads again?"* → profile-name-is-sacred rule++Direct user quote on the meta-rule: *"our users can help build out this skill as they need specific parts. so you should always show them the product page when you think you're at a dead end and let them help you figure out how to get the cad just like i have several times. then figure it out from their feedback and add to the skill for all other users. we can then make them almost be like a recursively learning loop from everyone."*++**Operational template** when the agent hits a dead end:++```bash+# 1. Foreground the page+adom-desktop browser_raise_os_window '{"sessionId":"chip-fetcher"}'++# 2. Screenshot for the chat+adom-desktop browser_screenshot '{"sessionId":"chip-fetcher","maxWidth":1500}'++# 3. Update activity badge so the dashboard shows "stuck — needs user"+curl -X POST http://127.0.0.1:8786/api/activity -d '{"mpn":"<MPN>","stage":"stuck — need user help"}'++# 4. Tell the user what you tried and ask one specific question.+#    GOOD: "WAGO product page has no .pdf anchor. The Generate Datasheet+#    modal opens but I can't find the CAD link. What do I click?"+#    BAD: "I couldn't find anything, what now?"++# 5. After the user answers, drive their suggested path AND+#    update SKILL.md (or the relevant playbook) with the new vendor-specific pattern.+```++## EDA-agnostic terminology in user-facing UI++**Adom is EDA-agnostic — chip-fetcher must support KiCad, Fusion 360 Electronics, Altium, OrCAD, EAGLE, and others.** Files on disk can be `.kicad_sym` / `.kicad_mod` (since KiCad's open format is the de-facto interchange), but **never expose those filenames as labels in the viewer or in user-facing CLI output**. Translate to neutral EDA terminology:++| under-the-hood file | user-facing label |+|--------------------|--------------------|+| `*.kicad_sym` | "SYMBOL" |+| `*.kicad_mod` | "FOOTPRINT" |+| `*.step` | "STEP" *(industry-standard, no translation needed)* |+| `*.pdf` | "PDF" or "DOCS" *(both are vendor-neutral)* |++Direct user quote: *"don't refer to stuff as MOD if what you mean by that is a footprint … we want adom to be applicable to all EDA software like kicad, fusion 360, altium, orcad, etc. so we don't want to go too heavy on any kicad references. its fine that we're using mod files under the hood, but we don't have to reveal that."*++Apply this rule to:+- Card badges in the viewer+- Filter labels ("missing footprint" not "missing MOD")+- CLI output (`chip-fetcher status` should print "footprint" not "mod")+- Status messages and tooltips+- Skill documentation when describing user-visible behavior
playbooks/manufacturer-direct.mdadded+244
@@ -0,0 +1,244 @@+# Manufacturer-direct (chip-fetcher playbook)++Per-vendor patterns for finding CAD + datasheets directly on the manufacturer's site. Read this when you've identified the manufacturer for an MPN and need to drive their specific page layout.++**All scraping in this playbook must run in pup `sessionId: "chip-fetcher"` (NOT the dashboard session) and must heartbeat every stage transition via `/api/activity` per [`dashboard-flow.md`](dashboard-flow.md).** Canonical stage labels: `probing <vendor>.com` → `found mfr-direct CAD` (or `no mfr-direct CAD — falling back to <source>`) → `downloading <format>` → `pulling from desktop` → `imported`.++## Confidence is not a substitute for the mfr probe++The rule isn't "check the manufacturer when uncertain." It's "always START at the manufacturer's site, even when 100% confident." Recurring violation pattern: AI recalls a known part family from training → queries Mouser to verify stock → recommends "want me to fetch this from SnapMagic?" — without ever opening `<mfr>.com`. **That is a direct skill-rule violation, even when the part really does exist on SnapMagic.**++Past direct user pushback (4+ repeats across sessions):+- *"i keep telling you to not go beyond the manufacturers website."*+- *"why do you keep not using the preference order i'm asking for?"*+- *"are you sure you couldn't navigate the lattice site? i feel like you give up too fast."*+- *"does renesas say to use 3dfindit.com? cuz if not, i don't like the idea."*++Some manufacturers self-host CAD that's better than the aggregators (Würth's UL-direct CAE icon, NXP's BXL bundles). Some have UL deep-links that are still mfr-direct because the link is on the mfr's page. Some don't host CAD at all and SnapMagic is the correct fallback. **You don't know which until you actually visit `<mfr>.com`.** 30 seconds of opening the page often changes the recommendation; pay the cost.++**Operational rule:** when a user asks for any chip / LED / connector / passive — even one you're 100% sure about — your FIRST action is `browser_open_window` on the manufacturer's product page. Walk Documentation, Tools & Software, CAD icon, Resources, Hardware Files. Scrape `<img alt>` for icon-only buttons. Only AFTER that probe is it OK to fall to SnapMagic / Mouser / DigiKey, and even then REPORT the mfr's state to the user before bouncing. Mouser stock-API queries can run in parallel as a side-channel, but they don't substitute for the mfr CAD probe.++## Self-hosting matrix++| Vendor    | Self-hosts STEP | Self-hosts symbol/footprint   | Datasheet hosting |+|-----------|-----------------|-------------------------------|-------------------|+| TI        | no (UL only)    | no (UL only)                  | direct, open URL  |+| ST        | no (UL only)    | no (UL only)                  | in-page fetch (CDN blocks curl) |+| ADI       | no (UL only)    | no (UL only)                  | in-page fetch     |+| **NXP**   | no              | **YES — BXL format** (mfr-direct) | direct PDF        |+| Microchip | no (UL gated)   | no (UL gated)                 | Microchip CDN     |+| Renesas   | no              | partcommunity (separate flow) | direct PDF        |+| Bosch     | NO CAD AT ALL   | NO CAD AT ALL                 | direct PDF        |+| Syntiant  | NO CAD AT ALL   | NO CAD AT ALL                 | NDA-gated         |+| **Espressif** | **YES via Mouser CSE Library Loader.** Both bare chips (ESP32-S3FN8) and modules (ESP32-S3-WROOM-1-N4) have full STEP+sym+footprint via mouser.componentsearchengine.com. | YES (same path) | **Open URLs at `www.espressif.com/sites/default/files/documentation/<mpn>_<doctype>_en.pdf`** — datasheet + TRM are huge (10–15 MB) and curl-able from container. |++For NXP specifically: BXL files are Accelerated Designs format — convert to KiCad via their Library Loader (Windows app) or treat as opaque mfr-authored asset.++## Vendor URL & UL deep-link patterns++Each manufacturer has its own product-page URL pattern, but most eventually link to a `vendor.ultralibrarian.com/<vendor-slug>/embedded` URL with a session-tied query string.++| Vendor        | Product page URL                                          | UL deep-link                                                |+|---------------|-----------------------------------------------------------|-------------------------------------------------------------|+| **TI**        | `ti.com/product/<MPN>`                                    | `vendor.ultralibrarian.com/TI/embedded/?gpn=<MPN>&...`      |+| **ST**        | `st.com/en/<category>/<mpn>.html`                         | `vendor.ultralibrarian.com/stmicro/embedded?rpn=<MPN>&...`  |+| **ADI**       | `analog.com/en/products/<mpn>.html`                       | `vendor.ultralibrarian.com/adi/embedded?vdrPN=<MPN>`        |+| **NXP**       | `nxp.com/products/<MPN>` *(self-hosts BXL — no UL)*       | n/a — direct `.bxl.zip` download                            |+| **Microchip** | `microchip.com/en-us/product/<mpn>` *(login-gated)*       | `vendor.ultralibrarian.com/microchip?vdrpn=<MPN>` *(in iframe)* |+| **Renesas**   | `renesas.com/en/products/<mpn>`                           | n/a — Renesas routes through CADENAS PartCommunity          |+| **WAGO**      | `wago.com/global/p/<MPN>`                                 | `vendor.ultralibrarian.com/Wago/Embedded/?vdrPN=<MPN>` *(via "CAE" icon)* |++Deferred: **Renesas** (CADENAS PartCommunity has its own auth flow), **Bosch / TDK / Allegro / etc.** (no CAD on their sites; need UL login).++## TI — open everything++Datasheets are trivial — `curl https://www.ti.com/lit/gpn/<base-mpn>` returns the PDF directly. No CAPTCHA, no login. Batch a whole list in one shell loop. Use `base-mpn` (e.g. `tps62840`, not `tps62840dlcr`) — that's the lowercase chip-family slug.++## Microchip iframe gotcha++Microchip embeds the UL form in a **cross-origin iframe** at `vendor.ultralibrarian.com/microchip?vdrpn=<MPN>`. `browser_eval` from the parent (microchip.com) page **cannot reach into the iframe** (CSP). Workaround: navigate the entire pup tab to the iframe URL directly. Then the form is at top level and the standard form-driver works.++```bash+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"https://vendor.ultralibrarian.com/microchip?vdrpn=ATSAMD51J20A-AUT"}'+```++Also: Microchip CAD is gated behind myMicrochip login. First-time use, OAuth popup opens — sign in with Google (uses the shared pup-profile Google session) or email/password.++## NXP product-page detail (don't quit early!)++NXP product pages have **icon-only CAD buttons** next to the "Data Sheet" pill that are easy to miss in a text-based DOM scrape:++1. **Symbol/Footprint icon** (small green tile, schematic-looking) — links to NXP's `/downloads/en/symbols-footprints/<MPN>-<package>-BXL.zip` (mfr-direct, no auth)+2. **3D icon** (small green tile labeled "3D") — fires `loadPartDiv('NXP','<MPN>','nxp',...)` which renders a **componentsearchengine** (samacsys) overlay div directly on the NXP page. The 3D STEP file lives behind that widget.++To find them programmatically:+```js+// Symbol/footprint URL (direct):+const ecad = document.getElementById('ecad_cta');  // <a href="javascript:loadPartDiv(...)">+const iconSrc = ecad?.querySelector('img')?.src;   // https://nxp.componentsearchengine.com/icon.php?...++// Trigger samacsys widget:+loadPartDiv('NXP','<MPN>','nxp',1,'zip',0,'','en-GB',0,'',0);+// Look for #mvOverlayDiv / #modalContainer / #mvBackdrop after this fires.+```++**Lesson learned the hard way:** when a vendor page seems to have "no CAD links," look for icon-only buttons via `<img>` `alt`/`src` attrs and parent `<a href="javascript:...">` triggers, not just text search. NXP and others bury the CAD entry behind a tiny styled icon.++**Don't navigate away from the vendor page** to chase guesses. The links you need are usually on the original page, just hidden behind an icon, accordion, or async-loaded section. Scroll, click tabs, expand dropdowns, inspect images.++### NXP login + EXTENDED PROFILE gotcha++- **NXP** open without auth: datasheet (`/docs/en/data-sheet/<id>.pdf`), block diagram (`/assets/block-diagram/...`), errata (`/docs/en/errata/...`), factsheet (`/docs/en/fact-sheet/...`), application notes (`/docs/en/application-note/AN<id>.pdf`), symbol/footprint BXL (`/downloads/en/symbols-footprints/<MPN>-<package>-BXL.zip`).+- **NXP** requires login: Reference Manual, Security RM, Hardware Design Guide, FRDM/EVK board user manuals — accessed via `/webapp/Download?colCode=<id>` which redirects to `login.nxp.com` (Azure B2C). Sign in with the user's NXP account, then re-fetch.+- **NXP requires an EXTENDED PROFILE** (Tell-us-about-yourself, business title, job description, company primary business, address) before unlocking Reference Manuals + Hardware Design Guides + Board User Manuals. Detect the redirect to `/webapp-signup/updateUser?userType=EXTENDED&mandatory=YES&TARGETURL=...` after a `colCode=` Download attempt and direct the user to fill that form (one-time per account). After submission, the original `colCode=` URL serves the PDF.++## Vishay — manufacturer-direct CAD via Design Tools page (verified 2026-05-03)++Vishay self-hosts 3D models as `.zip` files on their **Design Tools** page — full mfr-direct, no UL/CSE/SnapMagic bounce required. **This is the cleanest provenance tier.** Discovered by John pointing me at the page after I missed it on first walk.++### Design Tools URL pattern++```+https://www.vishay.com/en/how/design-support-tools/?category=<NN>+```++Filter UI on the page lets you set:+- **Design Tool Type** = `3D Model` (or `Symbol/Footprint`, `SPICE Model`, etc.)+- **Product Category** = `LEDs`, `Resistors`, `Capacitors`, `Diodes`, `Optoelectronics`, etc. (drives `?category=`)++The result is a sortable table with rows like:+| Design Tool Type | Description | Product Category | Share |+|------------------|-------------|------------------|-------|+| 3D Model | SMD 0402 ChipLED (*.zip) | LEDs | 🔗 |+| 3D Model | ChipLED Highbright 0603 VLMB1300 (*.zip) | LEDs | 🔗 |++Each row's `<a href="*.zip">` is a direct download — `https://www.vishay.com/docs/<doc-id>/<filename>.zip`.++### Family-level CAD (Vishay's strategy)++**Vishay publishes ONE zip per package family, not per MPN.** Example: `vlmx15xx.zip` covers the entire VLMx15xx 0402 ChipLED family — Super Red (VLMS1500), True Green (VLMTG1500), Blue (VLMB1500), White (VLMW1500), Soft Orange (VLMO1500), Yellow (VLMY1500), and others all share the same physical SMD 0402 body, so one STEP file applies to all of them. Per-part differences (color, wavelength, Vf) come from the datasheet, not the 3D model.++**Importer implication:** when fetching from Vishay's family-level zip, distribute the extracted STEP to EACH MPN's `library/<MPN>/<MPN>.step` directory. Tag `info.json` with:+```json+{+  "step_source": "mfr-direct",+  "step_authoring": "mfr-uploaded",+  "step_url": "https://www.vishay.com/docs/<doc-id>/<family>.zip",+  "step_note": "Family-level package body — covers all <FAMILY>xxxx parts. Color/wavelength/Vf differs per part; consult datasheet."+}+```++This pattern likely applies to other passive makers too (Würth, Murata, Yageo) — assume family-level until proven otherwise.++### Vishay naming conventions for indicator LEDs++| Code | Color |+|------|-------|+| `VLMS` | Super Red |+| `VLMB` | Blue |+| `VLMG` | Yellow Green |+| `VLMTG` | True Green |+| `VLMO` | Soft Orange (Vishay's amber-equivalent) |+| `VLMY` | Yellow |+| `VLMW` | White |++Series digits indicate package size:+- `1500` = SMD 0402 ChipLED Standard family+- `1300` = 0603 family+- `1400` = larger SMD or different brightness tier++**Distributor packaging suffix vs MPN:** the bare manufacturer MPN is `VLMS1500`. The `-GS08` suffix on Mouser/DigiKey listings is the **distributor's packaging code** (tape and reel options), NOT part of Vishay's MPN. Use the bare MPN as the library directory name. Mouser stock-API queries can use either form (`VLMS1500` works; `VLMS1500-GS08` resolves to specific reel SKU).++### What Vishay does NOT host++The Design Tools page filtered to "Symbol/Footprint" for LEDs returns very limited results — Vishay does not appear to publish KiCad/Altium symbols + footprints for indicator LEDs as cleanly as the 3D models. **Confirm by visiting individual product detail pages too** (sometimes vendors publish sym/mod separately on the part page rather than in the design-tools index).++If Vishay's part page also lacks sym/mod, the canonical fallback is:++1. **Mouser product page → "ECAD Model" link** (routes into `mouser.componentsearchengine.com/...` and serves a `LIB_<MPN>.zip` with `.step` + `.kicad_sym` + `.kicad_mod`).+2. The Mouser CSE bundle's STEP is mfr-uploaded too, but **Vishay's direct STEP is more accurate** — keep Vishay's STEP, take only the sym/mod from the CSE zip.+3. This is the "mfr-direct STEP + distributor-CSE sym/mod" hybrid pattern — tag `info.json`'s `sym_source` and `mod_source` separately from `step_source`:++```json+{+  "step_source": "mfr-direct",        "step_url": "https://www.vishay.com/docs/.../...zip",+  "sym_source":  "mouser-ecad-model", "sym_url":  "https://mouser.componentsearchengine.com/...",+  "mod_source":  "mouser-ecad-model", "mod_url":  "https://mouser.componentsearchengine.com/..."+}+```++Direct user direction during the verifying session: *"if you fail [on Vishay sym/mod], then it would seem you should try to then find that product on mouser and use their symbol/footprint and we'll join the two up. i love that you found the step though cuz i want the most accurate part 3d files."*++**Translation:** mfr-direct STEP is non-negotiable for accuracy. Sym/mod can come from the Mouser-CSE fallback because they're geometric (pad placement is a geometric fact, not a wavelength curve) and CSE's mfr-uploaded copies are good enough.++---++## Lattice / iCE40 family — Documentation tab has 30+ PDFs++iCE40 UltraPlus has a Documentation tab with 30+ PDFs (datasheet, hardware checklist, design guidelines, programming guide, all the IP usage guides, package diagrams, PCB layout, solder reflow, thermal management) — all at `https://www.latticesemi.com/view_document?document_id=<N>`. None of these are in the `<chip-page>/links` scrape — you have to click the Documentation tab to see them all listed.++User pushback on bailing too quickly: *"are you sure you couldn't navigate the lattice site? i feel like you give up too fast."* **Always click the Documentation tab and scrape ALL `view_document` URLs you find.**++## Sources have rich scene graphs (TI verified)++Confirmed across 8 TI parts grabbed via UL — UL ships **manufacturer-grade B-Rep STEPs with named PRODUCTs**:++| MPN | Package | PRODUCTs (named) | Faces | Cyl | Sph |+|---|---|---|---|---|---|+| TPS62840YBGR | DSBGA-6 | `product` | 15 | 1 | 6 |+| INA226AIDGSR | VSSOP-10 | `BODY-SO`, `LEAD-SO`, `PIN1-ID`, `DGS0010A_ASM` | 64 | 24 | 8 |+| LM358APE4 | PDIP-8 | `BODY_P0008A`, `LEAD_P0008A`, `LD_LHALF`, `LD_RHALF`, `ASM` | 90 | 30 | 8 |+| DRV8316RRGFR | VQFN-40 | `FRAME`, `BODY`, `QFN_ASM` | 635 | 160 | 0 |+| MCF8316A1RRYR | VQFN-40 | `FRAME`, `BODY`, `QFN_ASM` | 635 | 160 | 0 |++These are exactly the named-scene-graph signals adom-chiplinter Mode 0 needs.++## Manufacturer "reference-layout" zips ≠ standalone chip CAD++When a manufacturer publishes a `<MPN>-reference-layout-<ver>.zip`, it's a full board-design bundle, NOT a standalone chip CAD. Verified on Nordic's nRF52840-CKAA portal: the 18 MB zip contains:++- `Altium Designer files/` — `.IntLib`, `.PcbDoc`, `.PrjPCB`, `.SchDoc` (6 board variants)+- `Bill of Materials/` — per-variant `.xls` files+- `Production files/` — Gerbers, drill (`.DRL`)+- `Schematic and Layout pdf files/` — board-level PDFs++**Where it goes:** keep in `library/<MPN>/reference-layout/<...preserve subdirs...>` as a separate artifact bucket. Don't try to extract STEP/sym/mod from the Altium files automatically. Surface it in the viewer as "Reference layout: <N> BOMs · <N> Altium variants · <N> Gerbers · <N> PDFs."++**This bundle does NOT fill chip-fetcher's `<MPN>.step` / `<MPN>.kicad_sym` / `<MPN>.kicad_mod` slots.** Mark the chip as still stub-on-CAD in the viewer when only reference-layout exists.++## When stuck on a vendor: show user + let them teach you++chip-fetcher is community-built and recursively-learning. When the agent hits a dead end:++1. **Open the product page in pup foreground** (`browser_raise_os_window`).+2. **Take a screenshot** so the user can see what page state the agent landed on.+3. **Ask one short question:** *"I can't find a CAD download path on this page — can you spot it? Click the right button or describe what you see."*+4. **Wait for the user's hint.**+5. **Implement the path the user described.**+6. **Capture the new pattern back into this skill** with a vendor-specific section so the next agent doing the same vendor's part finds it automatically.++Direct user quote: *"our users can help build out this skill as they need specific parts. so you should always show them the product page when you think you're at a dead end and let them help you figure out how to get the cad just like i have several times. then figure it out from their feedback and add to the skill."*++Failure modes pushed back on:+- Went to 3dfindit.com because Renesas didn't surface CAD on the chip page → user: *"does renesas say to use 3dfindit.com? cuz if not, i don't like the idea of using it."*+- Jumped to Mouser CSE for the iCE40UP5K STEP without exhausting Lattice → user: *"are you sure you couldn't navigate the lattice site? i feel like you give up too fast."*+- Tried to use SnapMagic for BME688 → user: *"those other services like snapmagic don't have good 3d files."*++## Grab ALL design-help PDFs while you're on a vendor page++Datasheet alone isn't enough for an EE: also pull errata, hardware design guides, app notes, reference designs, anti-counterfeit guides, package mechanical drawings, IBIS models. EEs need the complete doc set. **Save each as `library/<MPN>/<MPN>-<doc-type>.pdf`** (e.g. `MCXN947VNLT-errata.pdf`, `MCXN947VNLT-hwguide.pdf`, `MCXN947VNLT-appnote-spi.pdf`). Don't pop in to grab just the STEP and leave — every page visit is an opportunity to harvest the full design package.++## Provenance tag in info.json++Always tag the source so downstream tools know the trust level:++```json+{+  "step_source": "mfr-direct" | "mfr-via-UL" | "mfr-via-CSE" | "mouser-ecad-model" | "mouser-cse-fallback" | "snapmagic" | "ul-main-search",+  "step_authoring": "mfr-uploaded" | "third-party",+  "verified_by": "FILE_NAME header / SamacSys preview / etc.",+  "source_url": "<the URL the file came from>"+}+```++Trust order: `mfr-direct` > `mfr-via-UL` > `mfr-via-CSE` > `mouser-ecad-model` > `mouser-cse-fallback` > `snapmagic` > `ul-main-search`. Anything tagged `"snapmagic"` or `"third-party"` gets demoted by adom-chiplinter's test-corpus weighting.
playbooks/mouser-cse.mdadded+149
@@ -0,0 +1,149 @@+# Mouser + Component Search Engine (chip-fetcher playbook)++Mouser is a first-class playbook (NOT a fallback tier) — it covers the long tail of chips without dedicated mfr CAD pages. Read this when manufacturer-direct doesn't host CAD, OR when you need stock + pricing + ECAD in one go.++**Heartbeat every stage** per [`dashboard-flow.md`](dashboard-flow.md). The slide-CAPTCHA escalation is a particularly important moment to heartbeat: post `mouser slide-CAPTCHA — user help needed` so the dashboard surfaces the stuck state, then raise the scraping window with `browser_raise_os_window` and let the user drag the slider. Don't silently wait — the user should see on the dashboard that we're stuck on Mouser.++## Mouser CSE Library Loader — the universal fallback (don't miss this)++**Critical pattern:** when a manufacturer has no CSE portal of their own (`<mfr>.componentsearchengine.com` returns `DNS_PROBE_FINISHED_NXDOMAIN`) AND no UL deep-link AND nothing on the mfr's own site, **check Mouser CSE**.++Pattern: `https://mouser.componentsearchengine.com/entry_u_newDesign.php?mna=<MFR>&mpn=<MPN>&pna=mouser&vrq=multi&fmt=zip&o3=0&lang=en-GB`++Mouser proxies CSE for any chip in their catalog, not just chips whose manufacturer paid for a dedicated CSE portal. It hits the same SamacSys library backend, returns the same mfr-uploaded STEP/symbol/footprint, with the same single CSE login.++### ⚠ TWO traps that make `entry_u_newDesign.php` return NO partID (both verified 2026-06-23, TI ADCs)++The entry endpoint returns one of three pages. Only one has a `partID`:+- **"SamacSys Part Preview"** (len ~50KB) → contains `partID=<N>`. ✅ This is what you want.+- **"SamacSys Part Selector" / "Pick One"** (len ~8–21KB) → a disambiguation page, **no partID**. ❌++Two independent causes push you onto the no-partID pages:++1. **Use the ORDERABLE MPN, not the base part.** `mpn=ADS1263` → "Pick One" (the base part has many package variants, so CSE can't resolve one). `mpn=ADS1263IPWR` (orderable, with package suffix) → "Part Preview", partID 755745. **Always pass the orderable MPN with its package/reel suffix.** If you only have the base MPN, a distributor parametric lookup (`adom-mouser`/`adom-digikey`) gives the orderable variant, or try the common suffix (TSSOP `…IPWR`, QFN `…IRTER`).++2. **Do NOT append `&logo=&epm=0` to the entry URL.** Those two extra params silently flip CSE into the "Part Selector" page (no partID) **even for a valid orderable MPN**. Use the minimal param set above. This cost an afternoon of "no-partID" debugging — the bug was a malformed URL, not the chip or the browser.++### `chip-fetcher cse <MPN> --mfr "<Manufacturer>"` — the automated path (use this first)++Does the whole CSE chain in code: navigate clean → entry (orderable MPN) → partID → preview → zipForm → `ga/model.php` → import STEP+symbol+footprint. Retries the cold-call flake and keeps the dashboard "working on" bar live via a heartbeat ticker. Prefer it over hand-driving URLs.++### How the download works — same-origin XHR + Basic-auth header (the breakthrough)++CSE downloads are HTTP Basic Auth. Inline-cred URLs (`https://user:pass@host/…`) are REJECTED by `fetch()`, and a plain navigate pops Chrome's invisible Basic-auth dialog. **The robust technique: a same-origin `XMLHttpRequest` (from a tab already on `mouser.componentsearchengine.com`) with `xhr.setRequestHeader('Authorization','Basic '+btoa(user+':'+pass))`.** XHR (unlike fetch) accepts the Authorization header AND pulls the bytes into JS as an arraybuffer — so the zip never hits Chrome's download policy (which silently blocks the 2nd+ download). This is what `cse_fetch_zip` in `pup.rs` does. **Vault-auth works in ANY browser** — the auth is the XHR header from chip-fetcher's vault, not a browser cookie, so CSE runs fine in the user's Chrome even if their saved CSE login lives in Edge.++**Real example:** Espressif has no CSE portal. Probing `espressif.componentsearchengine.com` gave NXDOMAIN. UL portal `vendor.ultralibrarian.com/espressif/embedded` gave "No Access is defined." But Mouser's product page for ESP32-S3FN8 had an "ECAD Model" block linking to `mouser.componentsearchengine.com/...` — and that path served a complete bundle. Same trick worked for the ESP32-S3-WROOM-1-N4 module.++## ⚠ HARD RULE — CSE downloads need credentials embedded in the URL++**Before you click any "Download CAD Models" button on `*.componentsearchengine.com`, embed credentials inline.** The `/signin` form-login session cookie is USELESS for downloads — those endpoints issue a separate HTTP Basic Auth challenge that pops a native Chrome dialog **invisible to `browser_eval`**. Symptom: page lands on `chrome-error://chromewebdata/`, no file in Downloads, nothing in DOM to indicate why. (Verified painful 2026-05-04.)++```bash+# Pull creds from chip-fetcher's vault, urlencode, prepend to URL:+CRED=$(curl -s http://127.0.0.1:8786/api/credentials | python3 -c '+import sys,json,urllib.parse+d=json.load(sys.stdin)+c=next((x for x in d["credentials"] if "componentsearchengine" in x["host"]), None)+if c: print(f"{urllib.parse.quote(c[\"username\"],safe=\"\")}:{urllib.parse.quote(c[\"password\"],safe=\"\")}")+')+URL="https://${CRED}@mouser.componentsearchengine.com/preview_newDesign.php?o3=0&partID=<ID>&ev=0&fmt=zip&pna=Mouser"+adom-desktop browser_navigate "{\"sessionId\":\"chip-fetcher\",\"url\":\"$URL\"}"+```++Always urlencode the username (`@` → `%40`) and password — special chars are common in CSE passwords. **Use this pattern by default for every CSE click that triggers a download.** Full diagnostic, OS-keychain alternative, and the two-vault sync requirement: see [`credentials-and-logins.md`](credentials-and-logins.md) § HARD RULE — CSE downloads use HTTP Basic Auth.++**Discovery flow when you can't find CAD on a vendor's site:**+1. Use `adom-mouser part <MPN>` to get the Mouser product URL.+2. Navigate pup to that Mouser page.+3. Look for "ECAD Model" / "Library Loader" link/text on the product page.+4. Follow the CSE URL into `mouser.componentsearchengine.com/...` directly.+5. Drive the standard CSE Download flow (same as NXP CSE).++## Mouser — first-class playbook++**Mouser is the most important external resource chip-fetcher has after the manufacturer's own site.** It hosts the datasheet AND the ECAD bundle for nearly every chip in their catalog — and for the long tail of chips whose manufacturers don't publish CAD (Vishay passives, niche connectors, smaller-vendor SoCs), Mouser is the *only* source.++Direct user quote: *"mouser is a key resource here so we have to get into the skill how to work with their website."*++**What's on every Mouser product page (right sidebar):**++- **`Datasheet:`** block — a `<MPN> Datasheet (PDF)` link. Either Mouser-CDN-hosted (`https://www.mouser.com/datasheet/<…>.pdf`) or a redirect to the manufacturer's CDN. Behind Akamai's bot wall, so use the in-page `fetch()` pattern, not naked curl.+- **`ECAD Model:`** block — `PCB Symbol, Footprint & 3D Model` link. Routes into `mouser.componentsearchengine.com/...` and serves a `LIB_<MPN>.zip` with `.step` + `.kicad_sym` + `.kicad_mod`.+- Extra reference docs (app notes, training PDFs) listed as additional `<a href="*.pdf">` rows further down — scrape them all.++## Operating manual — Mouser++1. **Always go through pup Chrome** — never naked curl. Their CDN serves a 174 KB HTML denial page (`"Access to this page has been denied because we believe you are using automation tools"`) for any non-browser request.+2. **Use the auto-cookie-accept helper** on every navigation — Mouser's cookie banner blocks downstream clicks via z-index.+3. **Use in-page `fetch()` with `{credentials:"include"}`** to pull PDFs (Chrome session cookies + JA3 fingerprint pass Akamai). Decode base64 result back into the library. `cf-mouser-pdf-pull.sh` is the reference implementation.+4. **For ECAD bundles, drive the full CSE Download flow inside the pup window.** Mouser-hosted CSE shares the same single-sign-on cookie as `componentsearchengine.com` proper, so once the user is signed in there, every Mouser ECAD link works without re-auth.+5. **Mouser's Search API (`adom-mouser`) gives you the canonical product URL + `datasheet_url` field for every variant.** Walk all variants — the version with the populated `datasheet_url` is sometimes a different package SKU than the MPN you searched for.++## Mouser's slide-to-verify CAPTCHA++After ~5–10 automated requests in a session, Mouser shows a slide-to-verify CAPTCHA. **Stop and ask the user to drag the slider.** Use `browser_raise_os_window` + `browser_screenshot` to surface the obstacle, then say: *"Mouser hit me with a slide-CAPTCHA — please drag the slider on the pup window to clear it."* Resume the flow once the CAPTCHA clears.++**DO NOT pivot to a different source for ECAD bundles** — there is no other source for those. Direct user pushback: *"that was a good test case … you can't just abandon the website if that's the only way to get the step file and symbol/footprint and the datasheet."*++**Cooldown:** Mouser's verification token persists for 30+ minutes after the user clears the slider. Batch your Mouser fetches during that window so the user only ever has to slide once per session.++**Critical caveat:** Mouser's CDN is Akamai-protected and rejects naked `curl` (returns 200 OK with a "Access to this page has been denied" HTML page). To pull a Mouser-hosted PDF you must either (a) navigate pup Chrome there and trigger a download (file lands in `~/Downloads`, then `chip-fetcher pull`), or (b) use in-page `fetch()` via `browser_eval` with `credentials:"include"` — Chrome's session cookies pass Akamai's bot check and the response can be base64-encoded back through `awaitPromise:true`.++## When the slider hits — escalation order++1. **Try `browser_input_dispatch type:"move"` along the slider track followed by `type:"click"` at the right edge.** Trusted CDP input has `isTrusted: true` and may pass GeeTest's basic acceleration check; some Mouser slider variants accept it.+2. **Pivot to vendor-direct ONLY if Mouser is fungible for this chip's docs.** TI lit IDs, ST `/resource/`, NXP `/docs/` — there are non-Mouser paths for documentation. Not for ECAD bundles.+3. **For ECAD bundles, there is no fungible path.** Hand off via `desktop_open_url` to the user's native browser (real Chrome with browsing-history reputation, extensions, real input). They slide once, the CAPTCHA token persists 30+ minutes, then the rest of the session works through pup again.+4. **Don't silently abandon a website if it's the only path.**++## CSE auth — single login covers all `<mfr>.componentsearchengine.com` subdomains++Sign in once at `https://componentsearchengine.com/signin` with the user's email + password, and the cookie covers every per-vendor subdomain (nxp, mouser, etc.). On first visit to a subdomain, an HTTP **Basic Auth** popup may appear once — it accepts the same CSE creds. After that, downloads on subdomain pages work.++The CSE STEP files we get for NXP/Mouser CSE are **mfr-authored, FreeCAD-exported** with named PRODUCTs (`ASSEMBLY`, `Body`, `ThermalPin`, `PinsArrayLR`, `PinsArrayTB`) — same authoring pipeline as TI's Fusion-electronics exports. So CSE-distributed STEPs match UL-distributed STEPs in scene-graph quality.++**Filename pattern: CSE downloads land as `LIB_<MPN>.zip` (vs UL's `ul_<MPN>.zip`).** The `cf-autowatch.sh` script's filename match needs to handle both — regex is `^(ul_|LIB_).*\.zip$`.++## Chrome's "wants to Download multiple files" SILENT KILLER++When CSE fires a download, Chrome detects multiple downloads (symbol + footprint + 3D + datasheet often arrive as separate transfers) and shows an Allow/Block dialog the first time per origin per session. **Programmatic `.click()` and `MouseEvent` dispatch CANNOT click Allow** — it's a Chromium browser-chrome dialog, not a page element.++Symptom: download button "works" (no error, page doesn't change), but `~/Downloads` stays empty for minutes.++**Cure: pre-grant the `automatic_downloads` permission to `*.componentsearchengine.com` BEFORE opening the page.** Two known approaches:+- (a) use Chrome DevTools Protocol `Browser.grantPermissions` via pup before the first navigation+- (b) launch the pup profile with `--auto-open-devtools-for-tabs` plus a setup script that flips the permission++**Do NOT ask the user to click Allow** — see "chip-fetcher does ALL the clicking" rule. Cloudflare/CSE reject curl-with-cookies attempts (HTTP 403 → CF anti-bot challenge → redirect to `/register`), so Chrome inside pup is the only viable path. Once the permission is granted at profile-load, all CSE clicks in that session run unattended.++(`chip-fetcher/scripts/adom-desktop-chrome-permissions-prompt.md` is the open feature request to bake `automatic_downloads: granted` into every pup `browser_open_window` by default.)++## Anti-detection / browse as a real user++Even when you go through pup Chrome, sites still profile *behavior*. Burst-clicking 5 product pages in 30 seconds with no scrolling, no mouse-movement, no referrer chain looks like a bot regardless of TLS fingerprint. The remedies, applied always:++1. **Pre-warm with a referrer chain.** Don't deep-link straight to a product page. Visit `<vendor>.com/` first, wait 3 seconds, then click into a search → results → product. Anti-bot heuristics weight `Referer` chains heavily.+2. **Add 2–5 second random delays between navigations** (`sleep $((2 + RANDOM % 4))`).+3. **Scroll the page after load.** Even one `window.scrollTo({top:600,behavior:'smooth'})` then a pause then `scrollTo({top:1400})` shifts behavioral profile out of bot territory and triggers lazy-loaded content.+4. **Move the mouse.** A few `dispatchEvent(new MouseEvent('mousemove', {clientX:..., clientY:..., bubbles:true}))` calls between clicks help.+5. **Don't fetch the same domain in tight bursts.** When backfilling 14 chips, space them ≥4 seconds apart and reload one tab — don't open 14 tabs at once.+6. **Use a single persistent profile (`chip-fetcher`)** so cookies, fingerprint, and visit history accumulate.+7. **Detection escape valve:** if a site still 403s despite all of the above, slow down and ask the user to slide whatever CAPTCHA appears.++## Always browse as a real user++**Every PDF fetch goes through pup Chrome with a real session, not naked `curl`.** Vendor CDNs (Mouser/Akamai, Cloudflare, ST/Akamai, Nordic/Cloudflare, NXP/Cloudflare) actively profile traffic for "automation tools" — TLS fingerprint, header order, missing `sec-ch-ua`/`sec-fetch-*`, no JS execution, no cookies, no referrer chain.++**The rule: every fetch flows through pup.** Use one of these in priority order:++1. **In-page `fetch()` via `browser_eval`** with `{credentials:"include"}` and `awaitPromise:true`, base64-encoding the response body back through the JSON channel.+2. **Programmatic `<a>` click in the rendered page** — Chrome handles the download natively, file lands in `~/Downloads`, then `chip-fetcher pull <path>`.+3. **Naked `curl` ONLY for vendor-doc CDNs that are confirmed not behind a bot wall** — TI's `ti.com/lit/pdf/<id>` is one of the few that works. **Always validate by checking the first 4 bytes:**+   ```bash+   head -c 4 "$OUT" | grep -q "%PDF" || { echo "not a real PDF"; rm -f "$OUT"; }+   ```+   If the magic check fails, the vendor served a denial page. Re-route through pup.++**Never write a backfill script that does `curl ... > out.pdf` without the `%PDF` magic-byte gate.** A 174KB HTML denial page mis-stored as a `.pdf` is worse than a missing file.++Direct user pushback: *"make sure we never get errors like this. meaning always browse as a real user would."*
playbooks/snapmagic.mdadded+146
@@ -0,0 +1,146 @@+# SnapEDA / SnapMagic (chip-fetcher playbook)++Verified end-to-end 2026-05-03 on nRF52840-CKAA-R7 — KiCad + Altium + Fusion in one session. Read this when the manufacturer doesn't host CAD directly (Nordic, niche connectors, passives, smaller-vendor MCUs).++**SnapEDA is a TIER 2 fallback — only use it AFTER confirming the manufacturer doesn't host CAD on their own site.** When falling back, post a `no mfr-direct CAD — falling back to SnapEDA` heartbeat so the user sees on the dashboard that we're leaving manufacturer-direct (per [`dashboard-flow.md`](dashboard-flow.md)). All format-cycling stages (kicad → altium → fusion) get their own heartbeats: `setting preferred format altium`, `clicking download symbol+footprint`, `dismissing heads-up`, `pulling altium IntLib`, etc.++## What it is++**SnapEDA is `snapeda.com` (host) but rebranded to "SnapMagic Search" in the UI.** Free CAD downloads (symbol + footprint + STEP + 3D + Altium/KiCad/Eagle/OrCAD/PADS/TARGET/Allegro) for millions of parts. **Account required for downloads.** Most embedded engineers already have one — ASK first per the credentials playbook.++**Where SnapEDA shines:** parts that aren't in CSE/UL — Nordic (no UL deep-link), niche connectors, passives, smaller-vendor MCUs, anything where the manufacturer doesn't publish CAD directly.++## Login flow (verified working)++```bash+# 1. Navigate to login page+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"https://www.snapeda.com/account/login/"}'+sleep 5++# 2. Fill credentials + form.submit() (NOT button click — the "Log In" looks like an <a> but+#    button-click doesn't fire the real handler; only form.submit() works)+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"(()=>{const u=document.querySelector(\"input[name=username]\"); const p=document.querySelector(\"input[type=password]\"); const proto=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,\"value\"); proto.set.call(u,\"<email>\"); proto.set.call(p,\"<password>\"); [\"input\",\"change\",\"blur\"].forEach(t=>{u.dispatchEvent(new Event(t,{bubbles:true})); p.dispatchEvent(new Event(t,{bubbles:true}));}); u.closest(\"form\").submit(); return \"submitted\";})()"}'++# 3. Wait for redirect away from /account/login/ — typically lands on /home/+```++**Critical: SnapEDA's "Log in" button does NOT submit the form via click.** Use `form.submit()` directly. Verified painful pattern when button-click wasted ~30 seconds before figuring this out.++## Search + part-page flow++URL pattern: `https://www.snapeda.com/parts/<MPN>/<Manufacturer>/view-part/`. The Manufacturer slug is URL-encoded (`Nordic%20Semiconductors` for Nordic parts).++To search: `https://www.snapeda.com/search/?q=<MPN>` returns a list of matching variants.++## Download flow — KEY INSIGHT: format is gated by user account preference++The part page has three tabs: **"Symbol and Footprint"**, **"3D Model"**, **"Alternates"**. The "Symbol and Footprint" tab has TWO orange buttons side by side: full bundle (`Download Symbol and Footprint`) and footprint-only (`Download Footprint`).++**3D Model (STEP)** — direct, no format picker:+```bash+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"document.getElementById(\"download_step_model\").click()"}'+# Lands as <MPN>--3DModel-STEP-<id>.STEP. Always raw STEP regardless of preferred-format.+```++**Symbol + Footprint** is gated by a **per-account "Preferred ECAD format"** at `https://www.snapeda.com/account/email/`. Two settings drive the orange-button behavior:++1. **Preferred ECAD format** (radio `preferred_2d_format`): one of `altium_native`, `kicad_modv6`, `kicad_modv4`, `kicad_modv3`, `eagle`, `fusion_360`, `orcad_v17`, `orcad_v16`, `pads`, `diptrace`, `designspark`, `cr_8000`, `circuit_studio`, `ecadstar`, `easypc`, `express_pcb_plus`.+2. **Direct download toggle** (ON = skip the format-picker modal and go straight to the preferred format)++When toggle is OFF (the default), clicking the orange "Download Symbol and Footprint" opens a `Choose Download Format` modal showing ALL formats, with the preferred at the top. When toggle is ON, the modal is skipped — except for KiCad which still asks "V3 / V4 / V6 & later" version variant.++## Switching format programmatically++Clicking the radio auto-saves via AJAX (no submit button needed). Verified by header text updating to "Direct download - Preferred format: Altium":++```bash+# Set Altium as preferred (auto-saves on click)+adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"https://www.snapeda.com/account/email/"}'+sleep 4+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"document.querySelector(\"input[name=preferred_2d_format][value=altium_native]\").click()"}'+# Then go back to part page — orange button now serves Altium.+```++**Always restore the preferred format to whatever the user had originally** (typically `kicad_modv6`) at the end of the session — don't leave the account changed.++## The "Heads Up" warning++For parts with multiple symbol sections, a small modal interrupts the download with *"This part contains multiple symbol sections. View the sections to see all pinouts."* Click the orange "Ok, download this part" button to proceed:++```bash+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"(()=>{const b=Array.from(document.querySelectorAll(\"a, button\")).find(e=>e.offsetParent!==null && /ok.*download this part/i.test((e.textContent||\"\").trim())); if(b){b.click(); return \"clicked\";} return \"no heads-up modal\";})()"}'+```++This is benign — just a "did you know there are multiple sections" notification. Always click OK.++## Full proven 3-format sequence++```bash+PART_URL="https://www.snapeda.com/parts/<MPN>/<Manufacturer>/view-part/"++fetch_format() {+  local FORMAT="$1"  # altium_native | kicad_modv6 | fusion_360 | eagle | etc.+  # 1. Set preference (auto-saves)+  adom-desktop browser_navigate '{"sessionId":"chip-fetcher","url":"https://www.snapeda.com/account/email/"}' >/dev/null+  sleep 4+  adom-desktop browser_eval "{\"sessionId\":\"chip-fetcher\",\"expr\":\"document.querySelector('input[name=preferred_2d_format][value=$FORMAT]').click()\"}" >/dev/null+  sleep 1+  # 2. Back to part page+  adom-desktop browser_navigate "{\"sessionId\":\"chip-fetcher\",\"url\":\"$PART_URL\"}" >/dev/null+  sleep 5+  # 3. Click orange Download (use coords from canvas-main-btn rect, typically near (548, 704))+  adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"(()=>{const b=Array.from(document.querySelectorAll(\"a.canvas-main-btn, a.modal-trigger\")).find(e=>e.offsetParent!==null && /download symbol and footprint/i.test((e.textContent||\"\").trim())); if(!b)return\"no btn\"; const r=b.getBoundingClientRect(); return JSON.stringify({x:Math.round(r.x+r.width/2),y:Math.round(r.y+r.height/2)});})()"}'+  # ...trusted-click those coords...+  # 4. Modal opens: click the format button by visible text+  # 5. KiCad-only: pick V6 & Later. All formats: dismiss "Heads Up" → click "Ok, download this part"+  # 6. Watch Downloads for new file+}++fetch_format kicad_modv6   # → <MPN>.zip   (contains .kicad_sym + .kicad_mod)+fetch_format altium_native # → <MPN>.IntLib (raw IntLib, NOT zipped)+fetch_format fusion_360    # → <MPN>.lbr   (Eagle .lbr — Fusion eats Eagle natively)+```++## Verified filenames in user Downloads++No MPN-Format suffix, just `<MPN>` + native extension:++| Format radio | Filename in Downloads | What's inside |+|--------------|----------------------|---------------|+| `kicad_modv6` (after V6 & Later picker) | `<MPN>.zip` | `<MPN>.kicad_sym` + `<MPN>.kicad_mod` |+| `kicad_modv4`, `kicad_modv3` | `<MPN>.zip` | older-format KiCad files |+| `altium_native` | `<MPN>.IntLib` | binary Altium Integrated Library, not zipped |+| `fusion_360` | `<MPN>.lbr` | Eagle .lbr (Fusion 360 imports Eagle) |+| `eagle` | `<MPN>.lbr` | identical content to Fusion in many cases |+| `orcad_v17` / `orcad_v16` | `<MPN>.zip` | OrCAD/Allegro library |++**Repeat-download collisions:** if the user already has `<MPN>.lbr` from a prior Fusion fetch, a fresh Eagle fetch lands as `<MPN> (1).lbr`. Watch Downloads diff, not absolute filename.++## Importing into chip-fetcher library++```bash+# KiCad zip → auto-extracts to .kicad_sym + .kicad_mod+chip-fetcher pull "C:\\Users\\<user>\\Downloads\\<MPN>.zip" --mpn <MPN>++# Altium IntLib + Fusion .lbr — pull stages them in incoming/ but doesn't auto-import.+# Manually copy into library/ with explicit names so the viewer can find them:+chip-fetcher pull "C:\\Users\\<user>\\Downloads\\<MPN>.IntLib" --mpn <MPN>+cp incoming/<MPN>.IntLib library/<MPN>/<MPN>.IntLib++chip-fetcher pull "C:\\Users\\<user>\\Downloads\\<MPN>.lbr" --mpn <MPN>+cp "incoming/<MPN>.lbr" library/<MPN>/<MPN>-fusion.lbr  # disambiguate from Eagle if both fetched+```++**(TODO for chip-fetcher importer: handle `.IntLib` and `.lbr` natively — current importer only knows about KiCad zips and STEP files, leaves Altium/Fusion in incoming/.)**++## InstaBuild AI-generated parts++Some parts on SnapMagic are AI-generated rather than vetted by the SnapMagic editorial team. Banner reads *"You've created this part using our AI Model Generator. This part is only visible to you."* The download flow is identical, but the symbol/footprint quality should be inspected before committing to the design. The InstaBuild edit URL is `https://instabuild.snapmagic.com/?unipart_id=<id>&token=<token>` (linked from the banner).++## Account profile cache++If `user_profile.md` (personal memory) has a `Site logins` section listing SnapEDA's email, pre-fill it; otherwise ASK. Never store passwords — pre-fill email + ask user to type password once. Pup persists session via cookies after login (`chip-fetcher` profile name).++**Login URL:** `https://www.snapeda.com/account/login/`++Direct user reaction when this flow landed the STEP for nRF52840-CKAA: *"all adom users will be thrilled!"*
playbooks/sourcing-ladder.mdadded+136
@@ -0,0 +1,136 @@+# Sourcing ladder (chip-fetcher playbook)++The defining rule for where chip-fetcher looks for CAD + datasheets, in priority order. Read this when starting any new MPN fetch, or when debugging why the agent went to the wrong source.++## The ladder, in priority order++1. **Manufacturer's own site** (`ti.com`, `nordicsemi.com`, `nxp.com`, `st.com`, `analog.com`, `microchip.com`, `bosch-sensortec.com`, `wago.com`, `vishay.com`, `diodes.com`, `renesas.com`, `espressif.com`, `latticesemi.com`). Datasheet, app notes, errata, lifecycle status, and a "CAD" / "Tools & Software" link if they partner with UL/CSE.+2. **SnapEDA / SnapMagic** (`snapeda.com`) — free CAD downloads (symbol + footprint + STEP + 3D + Altium/KiCAD/Eagle/OrCAD/etc.) for millions of parts. **Login required (most EEs already have one).** Comprehensive coverage especially for chips that aren't on UL/CSE — including Nordic, niche connectors, passives, etc. Should come right after manufacturer-direct, before chasing CSE-direct or UL-guess URLs.+3. **Mouser** (`adom-mouser search "<MPN>"`) — stock + pricing always, plus Mouser product page can surface UL/CSE deep-links.+4. **DigiKey** (`adom-digikey search "<MPN>"`) — broader catalog, niche industrial parts.+5. **Arrow** (`arrow.com`) — niche distributor.+6. **CSE direct** / **UL direct** — only when the manufacturer routes you there from their own page.+7. **LCSC** (`lcsc.com`, `datasheet.lcsc.com`) — **LAST RESORT, AVOID IF POSSIBLE.** LCSC redistributes manufacturer datasheets and EasyEDA-imported CAD, but quality is uneven and we lose the manufacturer's own provenance. Only fall here when steps 1–6 all returned nothing usable, and even then prefer to surface "we couldn't find this on the manufacturer's site" to the user instead of silently grabbing from LCSC.++Direct user quote (2026-05-06): *"when you're falling back to mouser for the search, after that you should do digikey, and then only after that try lcsc. i really want to avoid lcsc at all costs, but it is in the list if we're desperate."*++**Stock data is independent of the ladder:** always pull `stock.json` from the Mouser API alongside, regardless of where CAD/PDFs come from.++## Why manufacturer first (the ironclad rule)++- Vendor docs are authoritative (latest revision, full set of app notes).+- Manufacturer pages link to UL/SnapEDA deep-links specifically for their parts — find them by following the "CAD" link FROM the vendor page, never by guessing URLs.+- Errata + lifecycle status from the vendor is authoritative.++Direct user quotes:+- *"i keep telling you to not go beyond the manufacturers website."*+- *"look at the manufacturer web pages then. i want you always doing that first anyway before looking at 3rd party sites like mouser/digikey."*+- *"the whole point here is we want to get files, especially step files, from the manufacturer. so you can't cheat. only fallback to places like mouser when you're desperate."*++**🔒 IRONCLAD RULE: never leave the manufacturer's own website without explicit user approval.**++**This applies EVEN WHEN you "already know" the part.** When the agent has high prior confidence about a part (e.g. "LTST-C190KRKT is a Lite-On 0603 red LED, SnapMagic has it"), the cognitive shortcut is to skip the mfr-site probe and jump to the known-source. **Don't.** The rule isn't "check the mfr site when uncertain" — it's "always START at the mfr site, even when confident, before recommending or fetching from anywhere else." Confidence about the part identity is not a substitute for confirming the manufacturer's own site state.++The failure pattern that repeatedly trips this: user asks "do we have indicator LEDs?" → agent recalls a known part family from training → queries Mouser for stock validation → recommends fetching from SnapMagic — without ever opening `<mfr>.com`. That's a direct skill-rule violation. Direct user pushback (recurring): *"why do you keep not using the preference order i'm asking for?"*++The right reflex: open the manufacturer's product page first, even if it takes 30 seconds. Lite-On has `liteonopto.com`, Würth has `we-online.com`, etc. Walk the page, look for CAD/Datasheet/3D Model links. ONLY after exhausting the mfr's site is it OK to talk about SnapMagic / Mouser-CSE / UL fallbacks.++What this means in practice:+1. **Stay on `<vendor>.com` only.** Don't bounce to `3dfindit.com`, `partcommunity.com`, `mouser.componentsearchengine.com`, `vendor.ultralibrarian.com`, `snapeda.com`, `componentsearchengine.com`, or any third-party site **unless the manufacturer's own page links there explicitly** (e.g. TI/ST/ADI/Microchip embedding a `vendor.ultralibrarian.com/<slug>/embedded` URL counts as mfr-endorsed; navigating to UL via Google search does NOT).+2. **If you can't find CAD on the manufacturer's site, REPORT that to the user.** Don't go hunting on aggregators silently. The user will tell you what to do.+3. **Mfr-uploaded ≠ mfr-direct.** SamacSys hosts mfr-uploaded models, but the discovery / distribution channel is still third-party. Always check the mfr's site FIRST, exhaustively, even if you "know" it's going to fail.+4. **Native non-KiCad formats are still mfr-direct.** Altium `.IntLib`, OrCAD `.olb`/`.dml`, EAGLE `.lbr`, Renesas `.dml`, NXP `.bxl` — all of these qualify as mfr-authored. Pull them and convert to KiCad later; don't reject them because they're not in our preferred format.+5. **Exhaust the manufacturer's site before reporting "not available."** Walk every tab (Design Resources, Documentation, Tools & Software, Software & Drivers, Documents & Downloads, Hardware Files), expand every "Toggle" / accordion, click every icon-only button, scrape every `<img>` `alt`/`src`, follow every PDF/zip link, navigate to every Package / Pinout / Mechanical Drawing subcategory.++## Where SnapEDA shines (Tier 2)++When the manufacturer doesn't publish CAD directly (Nordic for example — `nordicsemi.com` doesn't expose chip CAD, only firmware SDK + reference-board Altium files), SnapEDA is the next viable free source. It's free with a login, and **most embedded engineers already have a SnapEDA account**.++Direct user pushback when chip-fetcher missed SnapEDA on Nordic's nRF52840-CKAA dead-end: *"why haven't you tried that before?"* Answer: should have. Adding to the ladder permanently.++## NRND / EOL / Last-Time-Buy is a hard stop for chip-fetcher's own picks++When a manufacturer page (or distributor lifecycle field) says any of these, treat it as a hard signal that the part is on its way out of the market:++- "Not Recommended for New Designs" / "NRND"+- "End of Life" / "EOL" / "Obsolete"+- "Last Time Buy" / "LTB" / "Last Order"+- DigiKey/Mouser `lifecycle` field set to anything except `active` / "" / "Active"+- Bosch/ST "Phased out" / "Mature"+- TI "Lifecycle: NRND"+- Mouser "Discontinued"+- Vendor pages with the explicit warning banner at the top++**The rule:**++1. **If the user explicitly asked for that exact MPN** → fetch it AND surface the lifecycle warning prominently. *"Heads up — TI has TPS40190EVM marked NRND, expect availability to drop within 2–3 years; do you still want it or should I find an active equivalent?"* Pause and let them decide. Their design might already be locked to that specific part for a reason (existing PCB, qual'd component, BOM compatibility).+2. **If chip-fetcher was choosing the part on its own** (default library picks, "popular" suggestions, batch fills, "show me a good op-amp" requests) → **DO NOT add it to the library.** Pick an active replacement. NRND parts will be unbuyable for InstaPCB users in 1–3 years; baking them into Adom's default library means real boards won't be manufacturable at scale.+3. **Always include `lifecycle` + `lifecycle_warning` in the stored `stock.json`** so downstream tools (InstaPCB, BOM checker) can flag these without re-scraping.++Direct user quote: *"if the page says 'not recommended for new designs' that you take that seriously. let the user know if they asked you specifically to get that part, but if you were just thinking that part was a good idea for some reason, it's not a good idea."*++**Detection sources** (check all three):++```bash+# 1. Manufacturer page banners+adom-desktop browser_eval '{"sessionId":"x","expr":"document.body.textContent.match(/not recommended for new designs|nrnd|end of life|obsolete|last time buy|phased out/gi)?.slice(0,3)"}'++# 2. Mouser API+adom-mouser search "<MPN>" | jq '.components[0] | {lifecycle, stock_text, lead_time}'+# lifecycle != "" and != "Active" → flag++# 3. DigiKey API+adom-digikey search "<MPN>" | jq '.components[0].lifecycle'+```++**Viewer badge:** when lifecycle is non-active, render a red "NRND" / "EOL" badge next to the stock badge so it's immediately visible during library browsing.++## Track Mouser stock + pricing as first-class data++chip-fetcher isn't just a CAD library — it's the source-of-truth for whether each chip can actually be put into an InstaPCB build. Every chip in `library/<MPN>/` should have current Mouser stock + price metadata cached alongside the CAD bundle.++**stock.json schema:**++```json+{+  "checked_at": "2026-05-03T01:15:00Z",+  "primary_variant": "TPS25751DREFR",+  "primary_reason": "highest_stock",+  "variants": [+    {+      "mpn": "TPS25751DREFR",+      "mouser_pn": "595-TPS25751DREFR",+      "stock": 3276,+      "unit_price": "$2.99",+      "package": "DREF",+      "lifecycle": "Active",+      "lead_time": "...",+      "product_url": "...",+      "datasheet_url": "..."+    }+  ],+  "mouser": {+    "mouser_pn": "...",+    "in_stock": 2995,+    "expected_dates": [{"qty": 2995, "date": "2026-09-04"}],+    "min_order": 1, "multiple": 1, "lead_time_weeks": 20,+    "lifecycle": "active",+    "price_breaks": [{"qty": 1, "unit_price_usd": 4.14}],+    "product_url": "...",+    "rohs": true,+    "datasheet_url": "..."+  }+}+```++Direct user quote: *"we need to know stuff is in stock at mouser so we can build the instapcb for the user, so you should be tracking that data too in chip-fetcher cuz it's really important data."*++## Multi-package variant tracking++When `adom-mouser search "<MPN>"` returns more than one variant of the chip, save **every variant** to `stock.json` under `variants[]` — not just the best/first one. Downstream tools (InstaPCB BOM picker, schematic-to-board flow, alternate-part suggester) need to know the user's choices, especially when packages differ.++Worked example: TPS25751 has both TPS25751DREFR (3276 @ $2.99, package: DREF) and TPS25751SRSMR (1425 @ $2.66, package: SRSM/RSM). Storing only the highest-stock variant hides that the user can pick a different package for layout reasons.++**Discovery:** any time the Mouser `components[]` array length > 1 AND the MPNs differ in suffix (different package), treat as multi-variant. If MPNs are identical (just differ in `mouser_pn`), it's the same chip from different inventory pools — collapse those.++Direct user quote: *"when you see multiple variants like that from mouser, you have to track that to let the user know the choices later downstream."*
playbooks/ultra-librarian.mdadded+315
@@ -0,0 +1,315 @@+# Ultra Librarian (chip-fetcher playbook)++UL deep-link patterns, form quirks, captcha handling, atomic-submit pattern, watcher race-safety. Read this when the manufacturer's product page links to a `vendor.ultralibrarian.com/<slug>/embedded` URL.++## TL;DR — three flows, pick by URL host++| URL pattern | Flow | Captcha? | Driver script | Auth |+|---|---|---|---|---|+| `vendor.ultralibrarian.com/<vendor>/embedded` | **Embedded captcha-iframe** (the public, no-login route from manufacturer product pages) | reCAPTCHA gauntlet, iterative escalation | `cf-ul-fast.sh --phase pre-captcha/post-captcha` | none required, but anonymous |+| `app.ultralibrarian.com/details/<uuid>/<vendor>/<MPN>` | **UL Pro tick-and-click** (logged-in user; URL contains `?uid=…`) | **none** for logged-in users | `cf-ul-pro-batch.sh <MPN>` | UL Pro form-login, cookie in pup profile |+| `app.ultralibrarian.com/details/<uuid>/...` (no `?uid=`) | UL Pro detail, anonymous | yes — falls back to embedded captcha | `cf-ul-fast.sh` (after page transition) | none |++**Best practice 2026-05-04:** sign in to UL Pro once via `chip-fetcher login ultralib` (see [`credentials-and-logins.md`](credentials-and-logins.md)). Then `cf-ul-pro-batch.sh` drives every subsequent fetch with zero captcha — no iterative-grid AI-vision burn, no token-timeout race. Captcha-driven `cf-ul-fast.sh` is now a fallback for parts UL Pro doesn't carry, or for anonymous flows.++## UL Pro logged-in tick-and-click flow (cf-ul-pro-batch.sh)++When the chip-fetcher pup profile has a live `app.ultralibrarian.com` cookie (`Remember My Login` was ticked at sign-in time → 30-day persistent session), UL Pro detail pages serve a **direct download form** instead of a captcha-iframe.++### The exact two-click pattern (this is the bug-prone part)++There are TWO elements on the page both labeled "Download Now":+- **`<button class="btn btn-dark...">`** — opens the format-picker panel. Clicking this does NOT trigger a download.+- **`<a class="export-trigger">`** — actually submits the picked formats and triggers the download. Initially **hidden** (collapsed under the closed picker); only `offsetParent !== null` after the BUTTON has been clicked.++Calling the script in the right order:++1. **Click the BUTTON** to open the format picker. URL gets `?open=exports`.+2. **Tick the format checkboxes** (Altium Designer, Fusion360 PCB, KiCAD v6+, etc.) — these are now visible in the open picker.+3. **Click the A.export-trigger** to submit. UL Pro server-side processes the format conversion; the "Starting Your Download" modal appears.++A single-click pattern (just clicking whichever Download Now is visible first) **fails silently** — the BUTTON click opens the picker but the download never fires because the submit element wasn't clicked. Verified painful 2026-05-04: 6/8 chips timed out waiting for a download that was never submitted.++### Full flow++1. Search: `https://app.ultralibrarian.com/search?queryText=<MPN>` → first `a[href*=details]` is the part page.+2. Navigate to part page → URL becomes `https://app.ultralibrarian.com/details/<uuid>/<vendor>/<MPN>?uid=<userId>`. The `?uid=` confirms authenticated session — if absent, the cookie didn't take and you'll get re-routed through embedded captcha.+3. Click `<button>Download Now</button>` (visible BUTTON) — opens picker.+4. Tick checkboxes by **label text**: `Altium Designer`, `Fusion360 PCB`, `KiCAD v6+`, `STEP`, etc. The checkboxes share `name="exports"` and have an integer value identifying the format. There are ~40 export formats; pick what you need.+5. Optionally tick any consent checkbox the manufacturer requires (TI: `name="consent-TIInfoShare"`). **Verified not actually required for the download to succeed** — UL Pro proceeds without it. But ticking it satisfies the form's UI completeness check.+6. Click `<a class="export-trigger">Download Now</a>` (visible A) — submits.+7. UL Pro shows a "Starting Your Download" modal — server-side format conversion takes 2-15 seconds typically (claims "up to 2 minutes").+8. Poll `~/Downloads/` (or Windows Downloads via `adom-desktop shell_execute powershell ...`) for `ul_<MPN>.zip` newer than the click timestamp.+9. Pull via `chip-fetcher pull <Windows-path> --mpn <MPN>` to copy zip into `incoming/`.+10. Extract `*.SchLib`, `*.PcbLib`, `*.lbr` from the zip and copy to `library/<MPN>/<MPN>.{SchLib,PcbLib,lbr}`. The chip-fetcher `pull` step already imports `.kicad_sym`, `.kicad_mod`, `.step` — the manual distribute step is just for Altium + Fusion files (chip-fetcher's importer doesn't handle them yet).++```bash+./scripts/cf-ul-pro-batch.sh BQ25798RQMR+# Posts activity to /api/activity at every stage so the dashboard reflects progress.+# Output:  url, picker opened, ticked N, submitted via A, download <name>, distributed SchLib PcbLib lbr, OK <MPN>+```++### Coverage caveats — UL Pro doesn't carry every package variant++UL Pro is per-package, not per-MPN. Common gaps (verified 2026-05-04):++- TI ADS131M04**IPBSR** (TQFP-32 PBS package) — UL has IPWR/IPWT (TSSOP-32 PW package) but **not** the PBS variant.+- TI MCF8316A1RRYR — not on UL Pro at all (very new part).++**Don't ship a wrong-package Altium file.** When the search returns a different package suffix, mark it in `info.json` (`altium: "no UL Pro coverage for <package>"`) and try the manufacturer's product page (TI's "EDA Symbols and Footprints" link sometimes routes to a different UL flow that has more packages). For non-coverage parts, accept partial state — KiCad-only is better than KiCad + wrong-package Altium.++## Use the fast two-phase captcha script for the embedded flow — DO NOT drive UL step-by-step from chat++**`chip-fetcher/scripts/cf-ul-fast.sh`** is the canonical UL driver. It collapses the chained-LLM-call problem (each chat-side `browser_eval` adds ~2-5s of latency, easily eating the captcha's 2-minute token budget) into TWO calls with one AI vision step in between. Tight bash cadences (200ms token-poll, parallel tile dispatch, 0.5s post-Verify wait) match what a Rust implementation could do; the bottleneck post-vision is the `adom-desktop` HTTP relay, not the script.++```bash+# Phase 1 (one shell call): navigate → preset form → trusted-click I'm-not-a-robot+#                           → if image grid: screenshot iframe + crop with DPR scaling+./scripts/cf-ul-fast.sh --phase pre-captcha --url '<UL-URL>'+# Returns JSON: { stage:"image_grid", iframe_png:"/tmp/...", round:1, _hint:"..." }+#       OR:    { stage:"silent_pass" }++# AI does ONE vision step: read iframe_png_2x, identify (a) grid size, (b) prompt, (c) tiles.++# Phase 2 (one shell call): click tiles → click Verify → check round-N escalation+#                           → atomic-eval Submit on token → poll Downloads+#                           → pull → distribute to family MPNs+./scripts/cf-ul-fast.sh --phase post-captcha --tiles 4,9 --mpns A,B,C \+    --grid 3x3 --round 1+# Returns: { stage:"done", ul_zip:..., distributed_to:["A","B","C"] }+#  OR (iterative captcha): { stage:"image_grid_round_2", iframe_png:..., _hint:"..." }+#  → AI does another vision pass, calls phase 2 again with --round 2.+```++The script handles family-distribution: when one UL zip covers multiple MPNs (common for indicator passives where the package body is shared), pass `--mpns A,B,C` and the script copies sym/mod into each `library/<MPN>/`.++## UL rotates captcha approaches — adapt, don't hardcode++UL deliberately varies captcha to throw off AI vision:++- **Grid size**: 3×3 (9 tiles, 1.5× larger per tile) vs 4×4 (16 tiles, denser). AI MUST detect from screenshot and pass `--grid 3x3` or `--grid 4x4` to phase 2.+- **Type**: "Select all images with X" (one-shot — click matching tiles, click Verify, done) vs "Click verify once there are none left" (iterative — click matches, then NEW images appear in clicked tiles, may need multiple rounds).+- **Subject difficulty**: easy (cars, fire hydrants, traffic lights) vs harder (boats, bicycles, chimneys, palm trees) — AI may need to be aggressive about ambiguous tiles.+- **Image noise overlay**: some replacement tiles in iterative mode have heavy noise — usually means "newly-shown after a click; classify based on what's visible through the noise."++`cf-ul-fast.sh --phase post-captcha` detects iterative escalation automatically (post-Verify check: bframe still visible AND token still empty → re-screenshot → output `image_grid_round_N+1` for AI to do another vision pass). AI loops until token populates or captcha hard-fails.++## /compact your conversation BEFORE driving UL++A captcha token has a ~120-second life from the I'm-not-a-robot click. AI vision response time scales with conversation context size. **If your context is large (200K+ tokens), each vision turn can take 8-15s** — that compounds across iterative captcha rounds and burns the token budget.++**Before any non-trivial UL fetch, recommend the user run `/compact`** to trim context. Smaller context = faster vision responses = the captcha pass succeeds before the token expires.++**Heartbeat protocol is mandatory** — see [`dashboard-flow.md`](dashboard-flow.md). `cf-ul-fast.sh` calls `post_act` automatically at every stage so the dashboard reflects live progress.++## DO NOT drive UL with separate `browser_eval` chat-side calls++Anti-pattern (the slow path):++```+[chat] browser_navigate UL URL+[chat] browser_eval — open Choose CAD Formats+[chat] browser_eval — preset form+[chat] browser_input_dispatch — click captcha+[chat] browser_screenshot — see image grid+[chat] AI vision — pick tiles+[chat] browser_input_dispatch — click tile 1+[chat] browser_input_dispatch — click tile 2+[chat] browser_input_dispatch — click Verify+[chat] browser_eval — poll for token (×N)+[chat] browser_eval — Submit+[chat] shell_execute — poll Downloads+[chat] chip-fetcher pull+```++Each line carries 2-5s of LLM/network latency. By the time Submit fires, the token is dead.++**The right path: `cf-ul-fast.sh --phase pre-captcha`, AI vision, `cf-ul-fast.sh --phase post-captcha`. Two CLI calls, one vision step.**++## Auto-driving pattern (the win)++**`chip-fetcher/scripts/cf-ul-fetch.sh <MPN> <UL-deep-link>`** is the canonical end-to-end driver. It implements the atomic-submit pattern verified working across TI/ST/ADI/WAGO/Microchip flows.++`chip-fetcher/scripts/cf-drive.sh <MPN>` opens the TI product page, finds the embedded UL link (carries session-tied URL pre-loaded with right gpn + package + pin), navigates to it, clicks "Choose CAD Formats & Download", then sets the form via JS:++```js+document.getElementById("MfrThreeDModel").click();   // STEP+document.getElementById("KiCADv6").click();          // KiCAD v6++document.getElementById("TermsAndConditions").click();+const sel = document.querySelectorAll("select").find(s => /Metric/i.test(s.options[1].text));+sel.value = "2-2"; sel.dispatchEvent(new Event("change",{bubbles:true}));  // mm+```++`chip-fetcher/scripts/cf-autowatch.sh <MPN>` (background) does two things:+1. Polls `g-recaptcha-response` token every 2s. When length > 50, the user has solved CAPTCHA. **Verifies the active tab URL still matches the MPN's base part** (race-safety) before auto-removing `disabled` from `#SubmitLink` and clicking it.+2. Polls user's `~/Downloads` every 2s. When a `ul_*.zip` whose filename matches the MPN base appears, calls `adom-desktop pull_file` + `chip-fetcher import --mpn <MPN>`.++A PID lock at `/tmp/cf-autowatch.lock` prevents two watchers running simultaneously.++The user only has to click **one CAPTCHA per part**. Everything else is automated.++### Typical batch flow++```bash+cd /home/adom/project/chip-fetcher+./scripts/cf-drive.sh <MPN>+./scripts/cf-autowatch.sh <MPN> &+adom-desktop browser_raise_os_window '{"sessionId":"chip-fetcher"}'+# → user clicks CAPTCHA on the pup window (one click)+# → watcher auto-clicks Submit, polls Downloads, pulls + imports+```++While the watcher's running, `curl https://www.ti.com/lit/gpn/<base-mpn>` to grab the datasheet PDF in parallel — that endpoint is open, no auth.++## Vendor-specific UL form quirks++Different UL portals use different checkbox IDs:++| Portal     | STEP checkbox ID  | KiCAD v6+ ID |+|------------|-------------------|--------------|+| TI         | `MfrThreeDModel`  | `KiCADv6`    |+| Microchip  | `MfrThreeDModel`  | `KiCADv6`    |+| ST         | `MfrThreeDModel`  | `KiCADv6`    |+| ADI        | `ThreeDModel`     | `KiCADv6`    |++**Don't rely on IDs** — use the visible label "STEP" / "KiCAD v6+" with `byLabel(re => /^STEP$/i)` lookup. The cf-drive.sh script already does this.++## ON UL DOWNLOADS — grab the popular EDA formats + STEP++**On every UL download form, check the popular-EDA format checkboxes — not just KiCAD.** The user's current project may target one EDA tool, but Adom adds support for new EDA tools over time, and re-fetching every board for a different EDA tool would mean another reCAPTCHA toll per part. **UL also caps free downloads at ~5 format selections per submission**, so picking smartly matters — going for "ALL formats" doesn't work.++**The canonical four-pick that covers >95% of user EDA tooling:**++- ☑ **STEP** (3D model — always, every download)+- ☑ **KiCAD v6+**+- ☑ **Altium Designer**+- ☑ **Fusion 360 PCB / Eagle**+- ☑ **T&C** checkbox (mandatory)++Direct user direction: *"i think the names i gave you are the right choice for now. we don't need ALL formats of other EDA's. just the popular ones … fusion 360 and altium and kicad."*++If the user later expands the supported EDA list (OrCAD, DesignSpark, Mentor, Pulsonix, Quadcept, TARGET, Zuken, CADSTAR, eCadstar — each is a separate UL checkbox), add to this list, but stay within UL's per-submission cap. For chips that need an EDA format outside the canonical four, do a second reCAPTCHA-gated fetch later (worth the toll).++**Footprint Units:** always set to **Metric (mm)** when the dropdown exists. Most EDA tools internally use mm; importing as mil and converting is a precision-loss tax.++**STEP picker:** if the page shows a "Cadenas 3D Model" dropdown (WAGO-style UL forms), pick `STEP AP214` (universal compatibility) or `STEP AP242` (newer, with PMI). If STEP is a checkbox (TI-style UL forms), just check it.++```bash+# Driver helper: pick the canonical four + T&C (no overflow)+adom-desktop browser_eval '{"sessionId":"chip-fetcher","expr":"(()=>{const cbs=Array.from(document.querySelectorAll(\"input[type=checkbox]\")); const want=[/^STEP$/i,/kicad v6/i,/^altium designer/i,/^fusion.?360/i,/agree|terms/i]; for(const re of want){const c=cbs.find(c=>re.test((c.parentElement?.textContent||c.closest(\"label\")?.textContent||\"\").trim())); if(c&&!c.checked) c.click();} return \"done\";})()"}'+```++If UL silently unchecks one (the "max 5" enforcement), the canonical four already fits — but if a vendor adds extra mandatory checkboxes (e.g. WAGO had Cadenas 3D Model dropdown which counts toward the cap), drop one of the EDA formats (typically Eagle/Fusion last) to stay under.++## reCAPTCHA v2 auto-click — try first, fall back to user only on image-grid++With `browser_input_dispatch` (adom-desktop ≥ v1.4.7), the agent CAN dispatch a trusted CDP click on the reCAPTCHA "I'm not a robot" checkbox iframe — **isTrusted is no longer the limiter**. What stops a clean silent pass is **Google's session-reputation scoring**: pup's Chrome-for-Testing has no browsing-history, no Google account session, no consistent IP usage pattern, so reCAPTCHA escalates to the image-grid challenge for low-reputation sessions.++**The empirical pattern (verified 2026-05-03 on TI UL):**++1. Move cursor toward the checkbox via `browser_input_dispatch type:"move"` with intermediate steps (helps fingerprint look human).+2. Click the checkbox at iframe `(left+30, top+40)` — that's where "I'm not a robot" sits inside the iframe.+3. Wait 3–5s.+4. Read `[name=g-recaptcha-response]`'s value.+   - Non-empty + `>20` chars → **silent pass, proceed to Submit**.+   - Empty + an image-challenge iframe (`iframe[src*=bframe]`) appears → **escalation, hand off to user**.++```bash+# 1. Find iframe coords+RECT=$(adom-desktop browser_eval '{"sessionId":"X","expr":"(()=>{const f=document.querySelector(\"iframe[src*=recaptcha]\"); if(!f)return null; const r=f.getBoundingClientRect(); return JSON.stringify({x:r.x|0,y:r.y|0});})()"}' \+  | jq -r '.result')++# 2. Move + click (humanlike approach)+IX=$(($(echo $RECT | jq .x) + 30))+IY=$(($(echo $RECT | jq .y) + 40))+adom-desktop browser_input_dispatch "{\"sessionId\":\"X\",\"type\":\"move\",\"x\":$((IX-200)),\"y\":$((IY-100)),\"steps\":5}"+sleep 0.5+adom-desktop browser_input_dispatch "{\"sessionId\":\"X\",\"type\":\"move\",\"x\":$IX,\"y\":$IY,\"steps\":15}"+sleep 0.4+adom-desktop browser_input_dispatch "{\"sessionId\":\"X\",\"type\":\"click\",\"x\":$IX,\"y\":$IY}"+sleep 4++# 3. Detect outcome: passed vs escalated+RESULT=$(adom-desktop browser_eval '{"sessionId":"X","expr":"JSON.stringify({tokenLen:(document.querySelector(\"[name=g-recaptcha-response]\")?.value||\"\").length, challenge:!!document.querySelector(\"iframe[src*=bframe]\")})"}')+# tokenLen >= 20 → passed, agent continues+# tokenLen == 0 && challenge true → image grid, AI vision can try, else user+```++**If escalated to image grid, AI vision CAN often solve it.** Verified working 2026-05-03 on TI UL: solved a 4×4 "traffic lights" grid + 3×3 "motorcycles" grid in two passes, token populated cleanly. Technique:++1. **Screenshot the iframe region.** The bframe iframe's bounding rect is exposed via `document.querySelector("iframe[src*=bframe]").getBoundingClientRect()`. Crop to `(rect.x * dpr, rect.y * dpr, rect.w * dpr, rect.h * dpr)` where `dpr = window.devicePixelRatio` (typically 1.5).+2. **Resize the crop 2× via ImageMagick** (`convert input -resize 200% out.png`).+3. **Read the prompt + grid.** "Select all squares with X" = 4×4 grid (16 tiles, click each square containing any pixel). "Select all images with X" = 3×3 grid (9 tiles, only the primary subject).+4. **Compute tile centers in browser CSS coords.** For 4×4 grid in iframe (273,127,400,580): grid area top≈237 left≈298, tile size ≈89×105 → tile (r,c) center = `(298 + (c-0.5)*89, 237 + (r-0.5)*105)`. For 3×3 grid: tile size ≈118×140.+5. **Click each correct tile via `browser_input_dispatch type:click`** with ~600ms between clicks (humanlike pacing).+6. **Click Verify** at iframe-bottom-right.+7. **Watch `[name=g-recaptcha-response]`** — token populating with >20 chars = passed.++**Token expires within ~2 minutes — Submit IMMEDIATELY after token populates.** Do NOT re-set form, do NOT add `sleep 8` between checks; that latency burns through the captcha lifetime and you'll have to solve it again.++## CRITICAL pattern — ATOMIC token-check + Submit-click in one `browser_eval`++**The winning pattern for UL captcha submits, verified end-to-end on TPS25751 2026-05-03.** Every prior attempt failed because the bash-side polling was `eval → check → eval` with 200–500ms round-trip between detection and Submit, which was enough for UL's backend to re-validate and reject the captcha token.++**Fix: do the check AND the click in a single `browser_eval`.**++```js+(() => {+  const t = (document.querySelector('[name=g-recaptcha-response]')?.value || '');+  if (t.length > 20) {+    const a = Array.from(document.querySelectorAll('a, button, input[type=submit]'))+      .find(e => /^submit$/i.test((e.textContent || e.value || '').trim()));+    if (a) { a.click(); return 'SUBMITTED_' + a.tagName; }+    return 'NO_BTN';+  }+  return 'WAIT';+})()+```++Bash polls this one eval at 1-second cadence — when it returns `SUBMITTED_*` you know Submit fired in the same browser tick the token was detected. **Net round-trip latency from token-populate to Submit-click: ~0 ms.**++**Other prerequisites that go with the atomic eval:**++1. **Pre-set the form BEFORE the captcha** (STEP + KiCAD v6+ + Altium + Fusion 360 + mm + T&C all in one eval). Zero work between token-detect and Submit.+2. **UL's Submit is an `<a>` tag**, not `<button>` — selector must scan `'a, button, input[type=submit]'`.+3. **Cache the Downloads-before snapshot BEFORE clicking reCAPTCHA**, not after Submit — else you race the download and miss the new file.+4. **Use the manufacturer's session-tied UL deep-link**, not `?vdrPN=` guesses. TI's product page has a `CAD` link that includes `gpn=<MPN>&package=<PKG>&pin=<N>&sid=<token>`. Without `sid`, UL silently routes to a wrong/related part. Verified: `?vdrPN=tps65987d` routed to `F280041RSHSR` (totally different chip).+5. **Verify part identity after navigation** — read `document.body.textContent` and confirm the MPN appears.++The full winning recipe lives in `chip-fetcher/scripts/cf-ul-fetch.sh`. Direct user reaction when this pattern landed the bundle on first attempt: *"you did it!!!!!! put that in the skill and/or make a script to be ready next time."*++## Even tighter timing for AI-vision-solved image grids++Verified 2026-05-03: even when AI vision passes a multi-stage image-grid challenge (4×4 → 3×3 → 4×4 → 3×3, ~3 challenges deep), **the cumulative time spent on screenshot + ImageMagick crop + Read + click cycles can exceed the 2-minute token window** by the time the FINAL Submit posts to the vendor backend.++**Mitigation when going AI-vision-solve route:**++1. **Pre-set the form completely** before triggering reCAPTCHA. STEP, KiCAD v6+, Altium, Fusion 360, Metric (mm), T&C — all set BEFORE you click "I'm not a robot."+2. **Keep ALL between-click latency under 1s.** No `sleep 4` for screenshots — use `sleep 0.6` between tile clicks.+3. **Skip screenshots after Verify.** Read `[name=g-recaptcha-response]` directly — that's the only signal that matters. If `.length > 20` → fire Submit in the SAME bash chain.+4. **Accept that 3+ challenge stages probably exceed the budget.** Plan for a redo, but expect the user to need to step in if Google keeps escalating. Direct user pushback on slow re-tries: *"why are you going so slow again? it'll timeout!!!"*++**The hard fact:** AI vision works for 1-stage image grids (~70% of trusted-click escalations). For 3+-stage chained challenges, the round-trip time of `screenshot → crop → read → identify → click → verify` is the bottleneck, not vision accuracy. For those, hand off to the user immediately.++**Reputation-building tips** for boosting silent-pass rate over time:+- Have the user sign into Google in the pup profile once.+- Visit a few high-reputation domains (google.com search, gmail.com) before the gated form.+- Use the same `chip-fetcher` profile across all sessions so cookies+history accumulate.++In practice, expect ~30–50% silent-pass rate on first attempts and increasing over time.++## Watcher race-safety (as of 2026-04-30)++`scripts/cf-autowatch.sh` enforces:+- **PID lock** at `/tmp/cf-autowatch.lock` — only one watcher at a time.+- **URL match** — verifies the active pup tab URL contains the expected MPN base before clicking Submit.+- **Filename match** — the Downloads-folder poll filters for filenames containing the MPN base, AND filename matches `^(ul_|LIB_).*\.zip$`.++Past incident: two watchers running simultaneously both saw the same CAPTCHA solve token and both raced to download/import the same UL zip — one ended up imported into the wrong MPN folder.++## UL gotchas++1. **UL download tokens are SINGLE-USE.** After Chrome consumes the URL once, server returns `Token Expired`. Re-fetching via `browser_eval` + `fetch()` will not work. **The only reliable path is `pull_file` from the user's Downloads folder.**+2. **UL ships PACKAGE-named files inside the zip**, not MPN-named. Inside `ul_TPS62840YBGR.zip` the STEP is `DSBGA6_1P4XP9_TEX.step`. Always pass `--mpn <MPN>` to import so files get renamed to `<MPN>.step`.+3. **UL ships multiple footprint variants** (default, `-L`, `-M`). Current import overwrites them all to one `<MPN>.kicad_mod`. TODO: disambiguate suffixes.+4. **TI does NOT self-host STEPs on ti.com.** Every TI part's "CAD/CAE Symbols" link is a UL deep-link with a session-tied URL.
skills/sites/nxp/SKILL.mdadded+18
@@ -0,0 +1,18 @@+---+name: chip-fetcher-site-nxp+description: >-+  How chip-fetcher pulls CAD from NXP (nxp.com) — the Design Resources / CAD+  section, sometimes behind an export-control click-through. Read before an+  NXP-direct fetch. Trigger words: nxp, nxp.com, nxp cad, nxp step, nxp symbol+  footprint, nxp export control, nxp blocked.+---+# Site: NXP (nxp.com)+Authoritative manufacturer source for NXP MCUs / analog / RF.+## Reach+- `https://www.nxp.com/products/.../<MPN>` or `google.com/search?q=<MPN> nxp.com cad`.+## Gate+- Free account + an **export-control / EULA click-through** on some STEP downloads.+## Download flow+- Product page → **Design Resources → CAD / Symbols & Footprints** (often a SnapEDA/SamacSys embed → hand to that site's skill); native STEP behind the EULA click.+## Catch / When it breaks+- Normalize into `library/<MPN>/`. Satisfy the EULA once via the profile. Embed instead of native CAD → follow the partner site's skill. Publish new flows (`../../CONTRIBUTING.md`).
skills/sites/st/SKILL.mdadded+18
@@ -0,0 +1,18 @@+---+name: chip-fetcher-site-st+description: >-+  How chip-fetcher pulls CAD from STMicroelectronics (st.com) — the CAD Resources+  tab on a product page, behind a free myST account for some downloads. Read+  before an ST-direct fetch. Trigger words: st, stm, stmicroelectronics, st.com,+  st cad, st step, stm32 cad, myst login, st blocked.+---+# Site: STMicroelectronics (st.com)+Authoritative manufacturer source for STM32 / ST analog & power parts.+## Reach+- `https://www.st.com/en/<family>/<MPN>.html` or `google.com/search?q=<MPN> st.com cad`.+## Gate+- A free **myST** account is required for some CAD/STEP downloads (a click-through login). Use the persistent profile; creds key `st`.+## Download flow+- Product page → **CAD Resources** tab → download the symbol/footprint and STEP. Some land as a `.zip`.+## Catch / When it breaks+- Normalize into `library/<MPN>/`. myST session expires → re-login once. ST gates exports by region/account; if a download 403s, confirm the myST session, then publish any new flow (`../../CONTRIBUTING.md`).
skills/sites/ultralibrarian/SKILL.mdadded+27
@@ -0,0 +1,27 @@+---+name: chip-fetcher-site-ultralibrarian+description: >-+  How chip-fetcher navigates Ultra Librarian / Component Search Engine (CSE/UL) —+  a late-ladder rung with broad coverage behind a login + format picker. Read+  before a CSE/UL fetch. Trigger words: ultra librarian, ultralibrarian, cse_ul,+  component search engine, samacsys, ul download, ul step, ul blocked.+---++# Site: Ultra Librarian / Component Search Engine (CSE/UL)++Late ladder (`cse_ul`) but wide coverage; many maker + DigiKey/Mouser "ECAD model"+buttons are CSE/UL or SamacSys embeds under the hood.++## Reach+- Search the UL/CSE catalog for `<MPN>`, land on the part, choose the ECAD target.++## Gate+- Free login; pick **KiCad** (symbol+footprint), **STEP**, and Eagle/Fusion ++  Altium when offered. Creds key `cse_ul` via `chip-fetcher creds`.++## Download flow / Catch+- Format picker → download `.zip` → pull + normalize into `library/<MPN>/`.++## When it breaks+- Login bounce → re-login once. Format picker reskinned → screenshot, find the+  KiCad/STEP options by label, update + publish (see `../../CONTRIBUTING.md`).