app
Pup - the AI's own browser
Public Made by Adomby adom
pup gives your AI a real browser on your desktop that it drives completely, in the background, signed in as you: windows that never jump in front of your work, one shared profile that learns your logins, and every window labeled on the taskbar with its AI thread's name.
← Commit history
Add pup-bridge-debug dev skill: symptom-indexed playbook for a misbehaving bridge (timeouts, dim LED, ~60s respawn loop, cold-start wedge) so today's root causes never get re-derived
2 files changed
+122
dev-skills/pup-bridge-debug/SKILL.mdadded+118@@ -0,0 +1,118 @@+---+name: pup-bridge-debug+description: "DEVELOPER debugging playbook for a MISBEHAVING Adom Desktop Puppeteer (pup) bridge — read this the moment pup feels broken, BEFORE re-diagnosing from scratch. Covers: pup verbs time out / hang, the AD bridge LED is dim, browser.bridgeRunning:false, the bridge keeps restarting / respawning every ~60s, opens succeed but the window vanishes or browser_list_windows is empty seconds later, a cold-start that never finishes, 'Chrome process exited immediately' storms, and how to tell a pup self-crash from AD reaping. Encodes the 2026-07-19 root causes (concurrent-launch wedge, crash-poison recovery loop, restart-reap-vs-respawn) so nobody re-derives them. Trigger words: pup timing out, pup verbs hang, pup not responding, pup bridge down, dim LED, bridgeRunning false, pup keeps restarting, pup respawn loop, bridge flapping, spawned with no reap, bridge_log_read, cold start stuck, Chrome exited immediately, window disappears, list_windows empty, pup wedged, recoverSessions crash, SingletonLock collision, pup diagnose."+---++Parent skill: **pup-bridge-dev** (build/publish). Companion: **pup** (user skill).++# pup-bridge-debug — diagnosing a misbehaving pup bridge (do NOT re-derive)++You are here because pup feels broken: verbs time out, the AD LED is dim, the bridge keeps+restarting, a window opened then vanished, or a cold start never finishes. **Every pattern below was+root-caused live on 2026-07-19 and cost real hours. Read this first — the answer is almost certainly+here.** The golden rule the whole day taught: **stop hammering a sick bridge and READ THE LOG.**++## Step 0 — the diagnostic toolkit (reach for these BEFORE guessing)++All are AD-**core** verbs (they do NOT route through pup, so they answer even when pup is dead):++| Tool | What it tells you |+|---|---|+| `adom-desktop --target <box> bridge_log_read '{"name":"puppeteer","lines":40}'` | **THE tell.** The AD lifecycle log (v1.9.93). Repeated `spawned process pid … (node.exe)` with **no reap between them** = pup is **self-crashing** and AD keeps respawning it. Note the cadence. |+| The AD GUI **bridge LED** | **Accurate liveness.** Dim = the pup process is not actively serving. Green = a verb spawned it and it's alive. |+| `status` → `browser.bridgeRunning` | Corroborates the LED. `false` = pup not serving. |+| `bridge_check_updates` → `liveVersion` / `staleProcess` | Version truth: `liveVersion` reads the RUNNING process's `/status`; `staleProcess:true` = running old code. |+| an actual pup verb replying | The ultimate liveness proof. |++**Liveness TRAP (cost a wrong "it's running" claim to John):** `bridge_list` `status:"running"` is+**NOT** liveness — it's desired/installed state and says "running" even when the process is down.+Trust the **LED + `browser.bridgeRunning` + a real verb reply**, never `bridge_list status`.++**Hygiene:** do NOT spam a sick bridge. Every pup verb against a down/wedged bridge burns a full 30s+AD relay timeout and *adds* congestion (a retry loop firing `browser_open_window` every few seconds+was itself part of the wedge on 2026-07-19). Use the AD-core tools above (they're instant), read the+log, THEN act once.++## Symptom → cause decision tree++- **pup verbs time out, but AD-core verbs (`status`, `bridge_log_read`) answer** → the pup PROCESS+ is down or wedged. Go to §Liveness/restart.+- **verbs time out, then briefly work, then time out again; LED flickers** → **flapping** (respawn+ loop). Read `bridge_log_read` — spawn-with-no-reap every ~N seconds confirms it. Go to §Crash loop.+- **`browser_open_window` returns `ok:true` (full response) but seconds later `browser_list_windows`+ is empty / the window is gone / even `desktop_list_windows` (AD-core) can't find it** → the process+ is **crashing right after responding**, then respawning fresh with no sessions. Go to §Crash loop.+- **cold start never finishes; several opens all say `bridge_starting`; readiness times out for+ minutes** → the **concurrent-launch wedge**. Go to §Wedge.+- **`Chrome process exited immediately` on every attempt** → stale profile lock / orphan Chrome, OR+ the wedge (two launches killing each other). Go to §Wedge.++## §Liveness/restart — `restart_bridge` REAPS; only some verbs RESPAWN (do NOT re-derive)++`restart_bridge` (and a crash) leaves pup **down** until AD auto-spawns it on the next call. But AD+spawns it for **window/tab verbs** (`browser_open_window`, `browser_list_windows`), **NOT** for a+bare status probe (`browser_readiness`, `status`). So **polling `browser_readiness` to "wait for pup+to come back" waits forever** — the probe never triggers a spawn and never reaches the down process.+This burned ~15 min on 2026-07-19.++**Recovery playbook (a down bridge):**+1. Fire **ONE** `browser_open_window` — it returns `bridge_starting` fast and triggers the spawn.+2. Then poll `browser_list_windows` (also auto-spawning) with **backoff** until it answers.+3. **Do NOT spam opens** while it says `bridge_starting` — one is enough; concurrent opens used to+ collide (§Wedge). `refresh_bridges {name:"puppeteer"}` (AD ≥1.9.76) is the download-and-restart+ path for UPDATES; `restart_bridge` is kill-and-respawn.++## §Crash loop — the ~60s respawn loop (native-crash poison, fixed v1.9.6)++**The pattern:** `bridge_log_read` shows pup spawned every ~60s for a long stretch, **even while+idle**, with no reaps. That cadence is AD's supervisor noticing a **dead** process and respawning it+— i.e. **pup is crashing on its own shortly after boot**, not being killed by AD.++**The mechanism (the key mental model):** pup's `process.on('uncaughtException')` /+`unhandledRejection` handlers only catch **JS throws**. A **NATIVE** crash — inside+`puppeteer.connect`, a CDP call, or a native module (`sharp`, `keytar`) — kills the process HARD and+**bypasses those handlers entirely**. So a `try/catch` around the risky op does **nothing** for a+native crash. On 2026-07-19 the trigger was `recoverSessions()` on boot: it rehydrates Chromes named+in `~/.adom/pup-sessions/*.json`, and a native crash during that reconnect killed the process+**before** the per-session catch could delete the offending file — so the **same poison file+re-crashed pup on every boot, forever**.++**Why a plain try/catch can't fix it, and what does:** the only defense against a native-crash-on-boot+loop is a **PERSISTENT (on-disk) circuit breaker**. Write an attempt-marker to the file **before** the+risky op; a file that still carries an incomplete attempt on the next boot is **quarantined**+(deleted, not retried); a clean recovery clears the marker; a graceful failure deletes the file. One+strike quarantines, so any poison file self-heals after a single crash instead of looping. That is+exactly what `recoverSessions` does now (`recoverAttempts` in the session file) — **do not remove+it.** Any NEW startup/periodic path that touches on-disk state and can crash natively needs the same+before-the-risky-op marker.++**Immediate stop-gap (get a flapping box usable NOW):** clear the recovery breadcrumbs —+`Remove-Item $env:USERPROFILE\.adom\pup-sessions\*.json`. No files → nothing to rehydrate → the+crash-on-boot can't fire. Then deploy the fixed bridge. **Confirm the fix by the LOG:** after the+restart, `bridge_log_read` should show **one** fresh spawn and **no more** — a stable process, not a+new one every ~60s.++## §Wedge — the concurrent-launch collision (fixed v1.9.4)++**The pattern:** a cold start that never finishes; multiple `browser_open_window`s all stuck on+`bridge_starting`; `Chrome process exited immediately` storms. **Cause:** a fresh profile is not in+the `browsers` map until its Chrome launch FINISHES (~10-15s), so two near-simultaneous opens for the+**same profile** (an AI retry/poll loop, OR two threads sharing a profile) each spawned their OWN+detached Chrome onto the **same `--user-data-dir`**. They then collided on Chrome's `SingletonLock`,+and each launch's lock-recovery `taskkill`ed "the orphan holding the profile" — which was the SIBLING+launch. They mutually killed each other; none came up; the bridge looked hung.++**The fix (do not remove):** `_launchInFlight` (Map `profileName`→Promise) in `getOrLaunchBrowser` —+the first launch per profile registers a Promise and concurrent callers **JOIN** it instead of racing+a second Chrome. **Corollary for callers/AIs:** never spam `browser_open_window` for the same session+while it says `bridge_starting`.++## The one-paragraph field guide (if you read nothing else)++pup misbehaving → **read `bridge_log_read` first.** Spawn-with-no-reap every ~N seconds = pup+self-crashing (native crash on boot; suspect on-disk poison in `~/.adom/pup-sessions/*` → the+`recoverAttempts` circuit breaker handles it, clearing the dir is the stop-gap). Verbs timing out with+a dim LED but AD-core answers = process down; a **status probe won't respawn it** — fire ONE+`browser_open_window` then poll `browser_list_windows`. Cold start stuck across several opens =+concurrent-launch wedge (already fixed by `_launchInFlight`; don't spam opens). `bridge_list+status:"running"` is not liveness — the **LED + browser.bridgeRunning + a real verb reply** are.
dev-skills/pup-bridge-dev/SKILL.md+4@@ -630,6 +630,10 @@ in that window. AI threads should NOT call this verb — they pass `wikiView` on ## Liveness, restart, and the concurrent-launch wedge (2026-07-19 — do NOT re-derive) +> **→ Full symptom-indexed playbook: the `pup-bridge-debug` skill.** Read that FIRST when pup is+> misbehaving (verbs timing out, dim LED, respawn loop, window vanishing). The notes below are the+> condensed version kept here for continuity.+ A live incident that ate an hour: after a `restart_bridge`, pup's verbs (`browser_readiness`, `browser_describe`, `browser_open_window`) all timed out for MINUTES and the AD GUI LED was dim. Three separate lessons, all now fixed/documented: