main
Kyle Bergstedt Publish 3.0.0 259e308 13d ago

name: pup-browsers-and-chrome user-invocable: true description: "MAINTAINER detail, not for a user's ears: how pup picks and launches its browser, and every cold-start / readiness case. A user hears 'pup window'; the build behind it (installed Chrome, Edge, or pup's own automation build) is answered only when asked (pup-bridge#114). Covers: the installed-browser-first architecture (launches a FRESH CDP-driven process of installed Chrome → else Edge → else cached Chrome for Testing, spawn-verified with fallthrough, caches the winner as default); pup_use to pin chrome/edge/cft/auto; INSTALLING real Google Chrome on an Edge-only box (pup_use install:true) including the UAC-approval-notify flow on locked-down machines; installing/prewarming Chrome for Testing; pup_readiness (READ-ONLY — the right 'is it ready / which browser' probe, NOT pup_status); the cold-start error table (node_not_found, bridge_restarting, chrome_for_testing_installing, chrome_install_no_disk, CfT 'skipped' is not a failure); AD-managed Node provisioning (no install needed on AD >=1.9.63); and the shell-approval gate. Read on any browser-pick question, a fresh/first-run PC, an install/prewarm, a not-ready error, or a shell-approval prompt. Trigger words: pup_readiness, pup_use, pup_prewarm, chrome for testing, install chrome, chrome_for_testing_installing, node_not_found, bridge_restarting, chrome_install_no_disk, cold start pup, which browser, edge only box, UAC approve chrome, request_shell_approval, shell command approval, adom runtimes, pup not ready."

Parent skill: pup-bridge · See also: pup (start here), pup-windows-sessions-tabs, pup-screenshots-recording.

pup — browsers, Chrome install & cold-start

How pup picks + launches a browser (the architecture)

POLICY (2026-08-10, pup 2.0.53+): pup's driving browser is Chrome for Testing. The dated record of why is docs/WHY-CFT.md on the wiki page — the policy has flipped twice, and the current flip is final: branded Chrome asserts the "controlled by automated test software" banner during real automation, and branded Chrome 137+ removed --load-extension, which the pup toolbar family needs. This section previously opened with "pup drives the browser already on the machine"; that was the mid-2026 policy and is REVERSED. What survives of it is the fallback ladder below, which is why a missing or still-downloading CfT never blocks an open. On every open pup builds a candidate list and spawn-verifies it:

  1. Pinned/cached default first (CfT, per policy) → installed Google Chrome → Edge → cached CfT. Chrome and Edge count only when they are installed in /Applications or ~/Applications.
  2. It launches a fresh process of that browser binary with an pup-managed --user-data-dir driven through pup's own extension channel (no debug port by default), never the user's signed-in profile, and a real rendered window (not headless).
  3. If the top pick is present but won't start (corrupt/partial install), pup falls through to the next — so an open never hard-fails on one broken browser.
  4. The browser that actually launched is cached as the default (persisted across bridge restarts) so it isn't re-probed each time.
  5. The CfT fetch (~150 MB) happens once — at prewarm, at first need, or when pinned via pup_use {browser:"cft"}. Installed Chrome/Edge are the FALLBACK, not the destination: expect a healthy box to report browserKind: chrome-for-testing in pup_readiness.

"Is it ready / which browser?" — pup_readiness (READ-ONLY)

adom-bridge-cli pup_readiness '{}'
# → {ready, browserKind:"chrome"|"edge"|"chrome-for-testing", browserSource, browserExecutablePath,
#    candidates:[…the full fallthrough list…], defaultBrowser, diskFreeMb, chromeStablePhase, …}
  • pup_readiness is the right probe — it never triggers a download and tells you exactly which browser will be driven + the candidate list + the default.
  • pup_status is NOT a readiness check — it only lists open sessions.
  • AD-core bridge_readiness is the platform-level "is this bridge up?" probe.

Pinning a browser — pup_use

pup auto-picks, but you can override (persists across restarts; launch still spawn-verifies + falls back):

adom-bridge-cli pup_use '{"browser":"chrome"}'   # pin installed Chrome
adom-bridge-cli pup_use '{"browser":"edge"}'     # pin Edge
adom-bridge-cli pup_use '{"browser":"cft"}'      # install Chrome for Testing (~150 MB once) + pin it
adom-bridge-cli pup_use '{"browser":"auto"}'     # back to auto-pick

Every pup_open_window response also carries browser (what was driven), availableBrowsers, and defaultBrowser — surface it if the user asks which browser pup is using.

Installing real Google Chrome

If the user specifically wants Chrome:

adom-bridge-cli pup_use '{"browser":"chrome","install":true}'
  • Downloads Google's official .dmg, copies Google Chrome into /Applications, then pins it. No prompt on a normal admin account.
  • Poll pup_readiness: chromeStablePhase goes installing → ready; browserKind flips to "chrome". pup keeps driving its current browser meanwhile, so nothing is blocked.

Installing / prewarming Chrome for Testing (the policy browser)

adom-bridge-cli pup_prewarm '{}'        # fetch CfT WITHOUT opening a window, then pin it (poll readiness)
adom-bridge-cli pup_use '{"browser":"cft"}'   # same, via the pin path

Worth running on ANY fresh box so the first real open skips the download (the fallback ladder covers the gap meanwhile). CfT reported as skipped is NOT a failure — on AD ≥ 1.9.76 the prewarm is conditional, so a box with a system browser skips the ~150 MB download and bridge_readiness shows the asset {present:false, skipped:true}. That's the intended installed-browser-first behavior; don't retry or report an error.

Cold-start error table — what a pup_open_window response can mean

Response Means Do
ok:true / a real session A browser was found + launched Proceed — the common case
errorCode:"bridge_restarting" (stillRunning:true) AD ≥ 1.9.77: verb landed in the brief gap while the bridge respawns after an install/update Poll pup_readiness until it answers, then retry the same verb — not a failure
errorCode:"chrome_for_testing_installing" (installing:true) RARE — no installed Chrome or Edge, so pup is fetching CfT in the background Poll pup_readiness until {ready:true}, then re-issue
errorCode:"chrome_install_no_disk" No browser + too little disk for CfT (readiness.diskFreeMb) Tell the user how much is free vs the ~800 MB needed; ask them to free space or install Google Chrome. Do NOT retry the download
errorCode:"chrome_install_failed" / chrome_download_network / chrome_install_permission No browser AND the CfT fallback download failed Read readiness.lastError; ask the user to install Google Chrome

Always surface a verb's _hint verbatim when it reports not-ready or failure.

No runtime to provision

pup on macOS is one signed binary: no Node, no npm, nothing for you or the user to install. Adom Bridge downloads, verifies and spawns it.

The shell-approval gate (rarely relevant to pup)

Core AD verbs and pup's own pup_* verbs (plus the desktop_record_* verbs pup answers for ab-core) run with NO desktop prompt. Only open-ended shell_execute / run_script pop AD's "Shell command needs approval" dialog — which you almost never need (prefer typed verbs). If one returns needs_approval / human_only on AD ≥ 1.9.86: run adom-bridge-cli --target <box> request_shell_approval (re-surfaces the dialog), ask the user to click Approve/Bypass, then retry your original verb. Never call shell_auto_approve (human-only, refuses). This is Adom Bridge's own gate.

Temporary pins and the toolbar (v2.0.378)

  • pup_use {browser:"chrome"|"edge", temporary:true} pins for a comparison or spike and expires at the next bridge boot (back to auto), so a forgotten pin can never strip the toolbar from every later launch. Pinning off CfT while the toolbar is on also returns a WARNING at pin time.
  • Any pup_open_window whose window launched on a browser that cannot carry the Adom toolbar (branded Chrome ≥137, Edge) returns _toolbarNotice saying so; CfT is the only toolbar-capable engine and the default policy converges onto it.

The download cache is pruned (2.0.677, pup-bridge#125)

Every build bump used to leave the previous build (~410 MB) in ~/.cache/puppeteer forever, plus headless-shell builds and partial downloads. pup now prunes a minute after every boot, keeping the pinned build, the newest complete build if the pinned one is missing, and anything a running browser or the saved default uses. pup_cache_prune {dryRun:true} shows what would go.