Adom Desktop - Puppeteer Bridge
Public Made by Adomby adom
The Adom Desktop Puppeteer (pup) bridge — drive a real headful browser on the user's desktop from the cloud: open/screenshot/eval/record. Cold-start drives the browser ALREADY on the machine (installed Chrome, else Microsoft Edge — every Windows PC ships with Edge) with a fresh isolated profile, so the common case needs NO download; Chrome for Testing is fetched only as a last resort. Two artifacts: the Releases zip is the bridge runtime (also bundled in Adom Desktop); the pkg installs the container-side Claude skills.
Handoff to the adom-desktop build thread — pup is now cloud-owned
Paste the block below into the adom-desktop build thread (the one that owns
github.com/adom-inc/adom-desktop). It mirrors what was done for the kicad/fusion bridges.
Subject: The Puppeteer (pup) bridge moved out of adom-desktop into its own wiki repo — please treat it like kicad/fusion now.
We took over code management of the Puppeteer bridge. It now lives at its own canonical wiki repo, exactly like the kicad and fusion bridges:
- Canonical repo / page: https://wiki.adom.inc/adom/adom-desktop-puppeteer-bridge
- Current published version: 1.1.0 (release asset + streaming manifest are live)
- Manifest (updateManifestUrl target):
https://wiki.adom.inc/api/v1/pages/adom-desktop-puppeteer-bridge/files/adom-bridge-puppeteer-manifest.json - Release zip:
https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.1.0/adom-bridge-puppeteer-v1.1.0.zip(sha256525eabb0350ea0eaf52a949e9b3026f5a4a035868afe9546a7478298b9539b8c, source-only — node_modules is reconstructed by AD'snpm installon spawn, as today)
What changed in 1.1.0 (the reason for all this): cold-start self-heal. On a fresh PC (HD bundles
AD; the installer pre-installs neither Node nor Chrome for Testing), the first "open in pup" used to
fail with a generic "Failed to launch Chrome after 3 attempts" + a dev string (npx…). Now the bridge
detects a missing Chrome for Testing, auto-installs it (programmatically via the bundled
@puppeteer/browsers), and exposes browser_readiness + browser_prewarm; /status reports
led/summary/tooltip truthfully (yellow while installing). The node_not_found path you already own is
unchanged and still correct.
Please make these adom-desktop changes (all small, mirroring kicad/fusion):
Keep pup a pre-installed bundled SEED (do NOT remove it from
bundle.resources) — same as kicad/fusion/blender. Fresh installs must still ship a working pup offline.Update the bundled seed
plugins/puppeteer/to v1.1.0 so a fresh install ships the cold-start fix even before the first wiki sync. Easiest: download + unzip the 1.1.0 release zip (URL above) intoplugins/puppeteer/(it's thesrc/tree at zip-root:server.js,chrome.js,bridge.json,BRIDGE_VERSION=1.1.0, etc.), keep the existing bundlednode_modules. The seed'sbridge.jsonalready declaresupdateManifestUrl(see #3).Confirm the seed
bridge.jsoncarriesupdateManifestUrl= the manifest URL above, so AD auto-pulls our updates (cache-over-bundled, numeric version_gt) viarefresh_bridges/ the 4h poll — exactly like kicad/fusion. (It's already set in the 1.1.0 source.) Add a shortplugins/puppeteer/CANONICAL.mdbreadcrumb pointing at the wiki repo, like the kicad/fusion seeds.Stop treating
plugins/puppeteeras the source of truth. Don't hand-edit it as if live and don'trelease-bridge.sh puppeteerfrom the adom-desktop repo anymore (it would clobber the cloud-owned page). pup is now in the same bucket as kicad/fusion inBRIDGE_OWNERSHIP.md/release-publish.shSKILLS_SRC — please add the same guard. (Also: pup's consumer SKILL now ships from the bridge's own wiki page, so droppup-SKILL.mdfrom the AD-core pkg's SKILLS_SRC to avoid a stale copy clobbering ours — same move you made for kicad/fusion.) ALSO remove"puppeteer"fromAD_CORE_SKILL_BRIDGESinbridge_registry.rssobridge_listreportsskillPkg = adom/adom-desktop-puppeteer-bridgefor the puppeteer bridge — that's what makes the dailysync_skillsauto-install the pup skills into every container. It's hardcodednull(skill-in-core) today, which is no longer true now that the skill ships from the pup page.THE ONE AD-CORE FIX WE NEED (we can't do this from the bridge): warm Node + Chrome for Testing on the HD-embedded first-run. Today the first-launch prefetch (
AUTOSTART_VERSIONtask inlib.rs, ~lines 3601–3607) is skipped when AD is embedded — which is exactly the HD-bundled fresh-PC case, so nothing pre-warms and the whole cold-start cost lands on the user's first "open in pup". Please either:- re-enable that idle-time prefetch task on the embedded path (it already calls
start_browser_bridge, which now self-installs Chrome for Testing), or - after AD enters embedded mode, fire
browser_prewarmonce (fire-and-forget) to kick the Chrome download in the background. Either way, gate it behind the existing Node check (if Node is missing it's a no-op / thenode_not_foundpath stays the recovery). Net effect: a fresh HD install quietly warms pup so the user's first "open in pup" is instant instead of a 2–3 min download.
- re-enable that idle-time prefetch task on the embedded path (it already calls
Verify after your change: on a fresh embedded boot with Node present, bridge_list shows pup at
1.1.0 (cache or seed), browser_readiness returns {ready:true} without the user ever asking, and
bridge_check_updates reaches the new page via updateManifestUrl. On a box without Node,
browser_open_window still returns the clean node_not_found → desktop_install_node path.
Questions / bugs in pup itself (a browser_* verb, a hint, the Chrome self-heal) → file them against
the wiki repo, not adom-desktop. Generic AD capabilities (a new lifecycle verb, the prewarm trigger
above) → adom-desktop, but don't re-absorb the bridge.
ALSO: the bridge-authoring docs are stale — please update them (affects EVERY new bridge author)
A new user asking "make me an adom-desktop bridge for " gets pointed at: the adom-desktop-bridges
Bridge SDK guide (#1 discovery hit), the adom-desktop-bridge-author skill, and the repo's
skills/BRIDGE_SDK.md (source). The RUNTIME guidance (bridge.json, verbs, health chip, rich hints,
lifecycle) is good + current. But the PUBLISH/PACKAGING guidance is outdated — and in one place WRONG.
These are AD-core-owned (we won't touch them, same as you don't touch pup), so please fix all three:
WRONG — "zip/bin under
/files".BRIDGE_SDK.md"Publish + iterate" (and theadom-desktop-bridgespage) tell authors the bridge zip goes on the page's/files. It does NOT —/filesstrips/rejects binaries. The zip is a RELEASE asset (adom-wiki release create+release upload); the manifest'surlpoints at the release download URL with a matchingsha256/size. (This is what fusion/kicad/pup actually do; following the doc as written produces a 404 manifest.)MISSING — the 3-artifact model. A bridge page ships THREE things and the docs only really explain one: (a) the release zip = the runtime AD streams into bridges-cache; (b) the pkg tarball (
adom-wiki pkg publish) = the container-side Claude/Codex skills (how the consumer skill reaches a container — completely absent today); (c) the optional bundled seed for AD-bundled bridges.MISSING — skill packaging + dev/user separation. (a) the pkg
filesallowlist + theskills/**glob trap (a bare"skills"entry ships ZERO skill files); (b) keep the tarball LEAN — NO zip, NOsrc/, NO hero PNGs (tar tzfto confirm; it was 16 MB before guards); (c) the wiki indexes EVERYSKILL.mdin the repo as an installable, Skills-tab-listed skill (skill_count) — so DEV/PUBLISH skills must be source-only, named NOTSKILL.md(e.g.dev-skills/*.md), or every user installs them.MISSING —
.codex/skills.install.shshould deploy the user skill to BOTH~/.claude/skillsand~/.codex/skills(Codex is a real second agent skills home now).MISSING — discovery triggers. Lead
discovery_triggerswith everyday USER phrases (not dev jargon) so "open my app in " surfaces the page; the discover snippet is auto-generated fromdiscovery_triggers+discovery_pitch(no separate upload step).STALE URL — the retired wiki host. Both the
adom-desktop-bridgespage AND theadom-desktop-bridge-authorskill still citewiki-ufypy5dpx93o.adom.cloud(retired). The only host iswiki.adom.inc. Grep + scrub (incl. thepage.jsonreadmebody).
Easiest path: lift the content from the pup bridge's now-canonical publish playbook —
wiki.adom.inc/adom/adom-desktop-puppeteer-bridge → dev-skills/pup-bridge-publish.md (it carries all six
points above, battle-tested) — and generalize the pup-specifics into the SDK guide.
⚠ CRITICAL (found LIVE 2026-06-29): a wiki-streamed pup CACHE copy CRASHES — no node_modules
When AD installs pup from the wiki — bridge_install {manifestUrl}, or refresh_bridges / the 4h poll
via updateManifestUrl — it streams the source-only zip into bridges-cache\puppeteer\ and spawns
node server.js, which **immediately crashes**: MODULE_NOT_FOUND on require('puppeteer') (server.js:10).
The cache copy has **no node_modules**, and AD's cache-spawn path does NOT npm install it or reuse the
bundled node_modules. Because **cache-over-bundled wins, this replaced a working bundled v1.0.16 with a
broken v1.1.0** (verified live on AdomLapper; reverted with bridge_uninstall). This is the Node-bridge
analogue of why kicad/fusion (Python, no node_modules) stream fine but pup can't.
Fix — please do ONE:
- (A) PREFERRED — give a cache-installed
spawn.kind:"node"bridge its node_modules. On spawn from the cache, AD should either (i)npm install/npm ciin the cache dir first (the bespokestart_browser_bridgeALREADY does this for the bundled pup — extend it to / route the cache copy through it), or (ii) reuse/symlink the bundlednode_modulesinto the cache dir. Then wiki-streaming +updateManifestUrlauto-update works for pup exactly like kicad/fusion. - (B) OR keep pup runtime "bundled-only" (the original model): the bundled-seed bump (handoff #2,
which KEEPS node_modules) is the runtime delivery; wiki-streaming the runtime stays off and
updateManifestUrlmust NOT pull a newer runtime into the cache.
Until (A) ships: do NOT publish a wiki pup RUNTIME version newer than the AD bundled seed — any box
with our updateManifestUrl persisted would pull the newer source-only zip into the cache and crash. The
skills pkg is unaffected (separate path, works). Net for now: ship the pup RUNTIME via the bundled
seed (#2); treat wiki-streaming as blocked on fix (A).
⭐ NEW TOP PRIORITY (found LIVE 2026-07-01 on 3 fresh Windows boxes): Node install = UAC + stale PATH dead-end
Tested cold-start on AdomLapper + two genuinely fresh boxes (AdomTestWin11 vbox, winvm Azure — both
Edge-only, no Node). The browser side is now solved by the bridge (v1.5.0: installed-browser-first,
spawn-verified fallback, self-warm, disk guards). The remaining cold-start blockers are both in AD-core
desktop_install_node and they hard-stop the exact "AI can't recover" scenario:
- UAC prompt.
desktop_install_nodeinstalls Node via the machine-wide MSI/winget, which is manifestedrequireAdministrator→ a UAC dialog pops on the user's desktop ("Node.js — OpenJS Foundation, allow changes?"). A cloud AI cannot click it; the user must, and John explicitly does not want a UAC here. - Stale PATH after a successful install. Even once Node installs, the already-running AD process
keeps its OLD environment, so the very next
browser_*STILL returnsnode_not_found/could not run npm for cache bridge. Reinstalling doesn't help (winget then says "No available upgrade" = already installed). The bridge can never spawn until AD is relaunched.
Both fixed by one change — install Node the portable, user-scoped way:
- Download the Node ZIP (
node-vXX-win-x64.zip), extractnode.exeinto a user-writable dir (e.g.%LOCALAPPDATA%\Adom Desktop\node\). No installer, no UAC. - Spawn bridges with that
node.exeby absolute path (AD already knows where it put it) — don't rely onPATHat all. This also permanently kills the stale-PATH class of bug. - Even better: bundle
node.exein the AD installer (~50 MB) so a fresh AD already has Node — zero download, zero UAC, zero PATH dependency, instant firstbrowser_open_window. - If you keep a PATH-based flow, at minimum probe common Node locations (
%ProgramFiles%\nodejs,%LOCALAPPDATA%\..., nvm dirs) before declaringnode_not_found, and refresh PATH from the registry after install.
Bridge-side hint already added (SKILL.md): if node_not_found persists after a successful install, the
AI is told AD's PATH is stale → relaunch AD (desktop_relaunch_self) rather than looping the installer.
RESOLVED: the wiki-streamed cache crash (node_modules) is fixed in AD ≥ 1.9.55
The earlier CRITICAL section (wiki-streamed pup CACHE copy crashes with MODULE_NOT_FOUND) is no longer
reproducing — on AD 1.9.55–1.9.62 the wiki-cache copy spawns cleanly (AD now reconstructs node_modules
on the cache bridge). All 3 test boxes ran the cache copy of pup 1.3.0→1.5.0 with source:"cache". So the
"ship runtime only via the bundled seed" constraint is lifted: the updateManifestUrl auto-pull works.
(Still bump the bundled seed opportunistically so a truly offline first-run is current.)
⭐ DESIGN PROPOSAL: AD-managed shared runtimes (Node + Python) — see PROPOSAL-shared-runtimes.md
The Node UAC/PATH pain above is a symptom of a bigger gap: no one owns bridge runtimes. Full write-up
in PROPOSAL-shared-runtimes.md (this repo). TL;DR of the recommendation (a hybrid, not either extreme):
- AD keeps a shared, content-addressed portable-runtime cache (
…\adom-runtimes\node-22.11.0\,python-3.12.7\), populated from portable zips into a user dir — no installer, no UAC. Ideally AD bundles one Node (+ Python) so a fresh box has it with zero download. - Bridges DECLARE their runtime in
bridge.json(runtime: {kind, version, preferred}) — they do NOT install it. pup ships this declaration as of v1.6.1. Shared interpreter when compatible; a pinned version fetched only when a bridge needs an odd one (no duplication for the common case). - AD spawns bridges by the interpreter's ABSOLUTE PATH (
…\adom-runtimes\node-22.11.0\node.exe server.js). This is the linchpin — it kills BOTH the UAC (portable/user-dir) AND the stale-PATH dead-end (no reliance on the machine PATH) at once. Python bridges get a per-bridge venv on the shared interpreter.
This replaces the per-bridge "roll your own Node" pattern (today's status quo, and the thing that caused
this whole debugging session). desktop_install_node's UAC MSI becomes a last-resort fallback.
# Handoff to the adom-desktop build thread — pup is now cloud-owned
Paste the block below into the adom-desktop build thread (the one that owns
`github.com/adom-inc/adom-desktop`). It mirrors what was done for the kicad/fusion bridges.
---
**Subject: The Puppeteer (pup) bridge moved out of adom-desktop into its own wiki repo — please treat it like kicad/fusion now.**
We took over code management of the Puppeteer bridge. It now lives at its own canonical wiki repo,
exactly like the kicad and fusion bridges:
- **Canonical repo / page:** https://wiki.adom.inc/adom/adom-desktop-puppeteer-bridge
- **Current published version:** **1.1.0** (release asset + streaming manifest are live)
- **Manifest (updateManifestUrl target):** `https://wiki.adom.inc/api/v1/pages/adom-desktop-puppeteer-bridge/files/adom-bridge-puppeteer-manifest.json`
- **Release zip:** `https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.1.0/adom-bridge-puppeteer-v1.1.0.zip` (sha256 `525eabb0350ea0eaf52a949e9b3026f5a4a035868afe9546a7478298b9539b8c`, source-only — node_modules is reconstructed by AD's `npm install` on spawn, as today)
**What changed in 1.1.0 (the reason for all this):** cold-start self-heal. On a fresh PC (HD bundles
AD; the installer pre-installs neither Node nor Chrome for Testing), the first "open in pup" used to
fail with a generic "Failed to launch Chrome after 3 attempts" + a dev string (npx…). Now the bridge
detects a missing Chrome for Testing, auto-installs it (programmatically via the bundled
@puppeteer/browsers), and exposes `browser_readiness` + `browser_prewarm`; `/status` reports
led/summary/tooltip truthfully (yellow while installing). The `node_not_found` path you already own is
unchanged and still correct.
**Please make these adom-desktop changes (all small, mirroring kicad/fusion):**
1. **Keep pup a pre-installed bundled SEED** (do NOT remove it from `bundle.resources`) — same as
kicad/fusion/blender. Fresh installs must still ship a working pup offline.
2. **Update the bundled seed `plugins/puppeteer/` to v1.1.0** so a fresh install ships the cold-start
fix even before the first wiki sync. Easiest: download + unzip the 1.1.0 release zip (URL above)
into `plugins/puppeteer/` (it's the `src/` tree at zip-root: `server.js`, `chrome.js`,
`bridge.json`, `BRIDGE_VERSION`=1.1.0, etc.), keep the existing bundled `node_modules`. The seed's
`bridge.json` already declares `updateManifestUrl` (see #3).
3. **Confirm the seed `bridge.json` carries `updateManifestUrl`** = the manifest URL above, so AD
auto-pulls our updates (cache-over-bundled, numeric version_gt) via `refresh_bridges` / the 4h poll —
exactly like kicad/fusion. (It's already set in the 1.1.0 source.) Add a short
`plugins/puppeteer/CANONICAL.md` breadcrumb pointing at the wiki repo, like the kicad/fusion seeds.
4. **Stop treating `plugins/puppeteer` as the source of truth.** Don't hand-edit it as if live and don't
`release-bridge.sh puppeteer` from the adom-desktop repo anymore (it would clobber the cloud-owned
page). pup is now in the same bucket as kicad/fusion in `BRIDGE_OWNERSHIP.md` /
`release-publish.sh` SKILLS_SRC — please add the same guard. (Also: pup's consumer SKILL now ships
from the bridge's own wiki page, so drop `pup-SKILL.md` from the AD-core pkg's SKILLS_SRC to avoid a
stale copy clobbering ours — same move you made for kicad/fusion.) **ALSO remove `"puppeteer"` from
`AD_CORE_SKILL_BRIDGES` in `bridge_registry.rs`** so `bridge_list` reports
`skillPkg = adom/adom-desktop-puppeteer-bridge` for the puppeteer bridge — that's what makes the daily
`sync_skills` auto-install the pup skills into every container. It's hardcoded `null` (skill-in-core)
today, which is no longer true now that the skill ships from the pup page.
5. **THE ONE AD-CORE FIX WE NEED (we can't do this from the bridge): warm Node + Chrome for Testing on
the HD-embedded first-run.** Today the first-launch prefetch (`AUTOSTART_VERSION` task in `lib.rs`,
~lines 3601–3607) is **skipped when AD is embedded** — which is exactly the HD-bundled fresh-PC case,
so nothing pre-warms and the whole cold-start cost lands on the user's first "open in pup". Please
either:
- re-enable that idle-time prefetch task on the embedded path (it already calls
`start_browser_bridge`, which now self-installs Chrome for Testing), **or**
- after AD enters embedded mode, fire `browser_prewarm` once (fire-and-forget) to kick the Chrome
download in the background.
Either way, gate it behind the existing Node check (if Node is missing it's a no-op / the
`node_not_found` path stays the recovery). Net effect: a fresh HD install quietly warms pup so the
user's first "open in pup" is instant instead of a 2–3 min download.
**Verify after your change:** on a fresh embedded boot with Node present, `bridge_list` shows pup at
1.1.0 (cache or seed), `browser_readiness` returns `{ready:true}` without the user ever asking, and
`bridge_check_updates` reaches the new page via `updateManifestUrl`. On a box without Node,
`browser_open_window` still returns the clean `node_not_found` → `desktop_install_node` path.
Questions / bugs in pup itself (a `browser_*` verb, a hint, the Chrome self-heal) → file them against
the wiki repo, not adom-desktop. Generic AD capabilities (a new lifecycle verb, the prewarm trigger
above) → adom-desktop, but don't re-absorb the bridge.
---
---
## ALSO: the bridge-authoring docs are stale — please update them (affects EVERY new bridge author)
A new user asking "make me an adom-desktop bridge for <X>" gets pointed at: the **`adom-desktop-bridges`**
Bridge SDK guide (#1 discovery hit), the **`adom-desktop-bridge-author`** skill, and the repo's
**`skills/BRIDGE_SDK.md`** (source). The RUNTIME guidance (bridge.json, verbs, health chip, rich hints,
lifecycle) is good + current. But the PUBLISH/PACKAGING guidance is outdated — and in one place WRONG.
These are AD-core-owned (we won't touch them, same as you don't touch pup), so please fix all three:
1. **WRONG — "zip/bin under `/files`".** `BRIDGE_SDK.md` "Publish + iterate" (and the `adom-desktop-bridges`
page) tell authors the bridge zip goes on the page's `/files`. It does NOT — `/files` strips/rejects
binaries. The zip is a **RELEASE asset** (`adom-wiki release create` + `release upload`); the manifest's
`url` points at the release download URL with a matching `sha256`/`size`. (This is what fusion/kicad/pup
actually do; following the doc as written produces a 404 manifest.)
2. **MISSING — the 3-artifact model.** A bridge page ships THREE things and the docs only really explain one:
(a) the **release zip** = the runtime AD streams into bridges-cache; (b) the **pkg tarball**
(`adom-wiki pkg publish`) = the container-side Claude/Codex skills (how the consumer skill reaches a
container — completely absent today); (c) the optional **bundled seed** for AD-bundled bridges.
3. **MISSING — skill packaging + dev/user separation.** (a) the pkg `files` allowlist + the `skills/**`
glob trap (a bare `"skills"` entry ships ZERO skill files); (b) keep the tarball LEAN — NO zip, NO
`src/`, NO hero PNGs (`tar tzf` to confirm; it was 16 MB before guards); (c) **the wiki indexes EVERY
`SKILL.md` in the repo** as an installable, Skills-tab-listed skill (`skill_count`) — so DEV/PUBLISH
skills must be **source-only**, named NOT `SKILL.md` (e.g. `dev-skills/*.md`), or every user installs them.
4. **MISSING — `.codex/skills`.** `install.sh` should deploy the user skill to BOTH `~/.claude/skills` and
`~/.codex/skills` (Codex is a real second agent skills home now).
5. **MISSING — discovery triggers.** Lead `discovery_triggers` with everyday USER phrases (not dev jargon)
so "open my app in <X>" surfaces the page; the discover snippet is auto-generated from
`discovery_triggers` + `discovery_pitch` (no separate upload step).
6. **STALE URL — the retired wiki host.** Both the `adom-desktop-bridges` page AND the
`adom-desktop-bridge-author` skill still cite **`wiki-ufypy5dpx93o.adom.cloud`** (retired). The only host
is `wiki.adom.inc`. Grep + scrub (incl. the `page.json` `readme` body).
**Easiest path:** lift the content from the pup bridge's now-canonical publish playbook —
`wiki.adom.inc/adom/adom-desktop-puppeteer-bridge` → `dev-skills/pup-bridge-publish.md` (it carries all six
points above, battle-tested) — and generalize the pup-specifics into the SDK guide.
---
## ⚠ CRITICAL (found LIVE 2026-06-29): a wiki-streamed pup CACHE copy CRASHES — no node_modules
When AD installs pup from the wiki — `bridge_install {manifestUrl}`, or `refresh_bridges` / the 4h poll
via `updateManifestUrl` — it streams the **source-only** zip into `bridges-cache\puppeteer\` and spawns
`node server.js`, which **immediately crashes**: `MODULE_NOT_FOUND` on `require('puppeteer')` (server.js:10).
The cache copy has **no `node_modules`**, and AD's cache-spawn path does NOT `npm install` it or reuse the
bundled `node_modules`. Because **cache-over-bundled wins, this replaced a working bundled v1.0.16 with a
broken v1.1.0** (verified live on AdomLapper; reverted with `bridge_uninstall`). This is the Node-bridge
analogue of why kicad/fusion (Python, no node_modules) stream fine but pup can't.
**Fix — please do ONE:**
- **(A) PREFERRED — give a cache-installed `spawn.kind:"node"` bridge its node_modules.** On spawn from
the cache, AD should either (i) `npm install`/`npm ci` in the cache dir first (the bespoke
`start_browser_bridge` ALREADY does this for the bundled pup — extend it to / route the cache copy
through it), or (ii) reuse/symlink the bundled `node_modules` into the cache dir. Then wiki-streaming +
`updateManifestUrl` auto-update works for pup exactly like kicad/fusion.
- **(B) OR keep pup runtime "bundled-only"** (the original model): the bundled-seed bump (handoff #2,
which KEEPS node_modules) is the runtime delivery; wiki-streaming the runtime stays off and
`updateManifestUrl` must NOT pull a newer runtime into the cache.
**Until (A) ships: do NOT publish a wiki pup RUNTIME version newer than the AD bundled seed** — any box
with our `updateManifestUrl` persisted would pull the newer source-only zip into the cache and crash. The
**skills pkg is unaffected** (separate path, works). Net for now: ship the pup RUNTIME via the bundled
seed (#2); treat wiki-streaming as blocked on fix (A).
## ⭐ NEW TOP PRIORITY (found LIVE 2026-07-01 on 3 fresh Windows boxes): Node install = UAC + stale PATH dead-end
Tested cold-start on AdomLapper + two genuinely fresh boxes (AdomTestWin11 vbox, winvm Azure — both
Edge-only, no Node). The **browser** side is now solved by the bridge (v1.5.0: installed-browser-first,
spawn-verified fallback, self-warm, disk guards). The remaining cold-start blockers are **both in AD-core
`desktop_install_node`** and they hard-stop the exact "AI can't recover" scenario:
1. **UAC prompt.** `desktop_install_node` installs Node via the machine-wide MSI/winget, which is
manifested `requireAdministrator` → a **UAC dialog pops on the user's desktop** ("Node.js — OpenJS
Foundation, allow changes?"). A cloud AI cannot click it; the user must, and John explicitly does not
want a UAC here.
2. **Stale PATH after a *successful* install.** Even once Node installs, the already-running AD process
keeps its OLD environment, so the very next `browser_*` STILL returns `node_not_found` /
`could not run npm for cache bridge`. Reinstalling doesn't help (winget then says "No available upgrade"
= already installed). The bridge can never spawn until AD is relaunched.
**Both fixed by one change — install Node the portable, user-scoped way:**
- Download the **Node ZIP** (`node-vXX-win-x64.zip`), extract `node.exe` into a user-writable dir (e.g.
`%LOCALAPPDATA%\Adom Desktop\node\`). **No installer, no UAC.**
- Spawn bridges with that `node.exe` **by absolute path** (AD already knows where it put it) — don't rely
on `PATH` at all. This also permanently kills the stale-PATH class of bug.
- Even better: **bundle `node.exe` in the AD installer** (~50 MB) so a fresh AD already has Node — zero
download, zero UAC, zero PATH dependency, instant first `browser_open_window`.
- If you keep a PATH-based flow, at minimum **probe common Node locations** (`%ProgramFiles%\nodejs`,
`%LOCALAPPDATA%\...`, nvm dirs) before declaring `node_not_found`, and refresh PATH from the registry
after install.
**Bridge-side hint already added (SKILL.md):** if `node_not_found` persists after a successful install, the
AI is told AD's PATH is stale → relaunch AD (`desktop_relaunch_self`) rather than looping the installer.
## RESOLVED: the wiki-streamed cache crash (node_modules) is fixed in AD ≥ 1.9.55
The earlier CRITICAL section (wiki-streamed pup CACHE copy crashes with MODULE_NOT_FOUND) is **no longer
reproducing** — on AD 1.9.55–1.9.62 the wiki-cache copy spawns cleanly (AD now reconstructs node_modules
on the cache bridge). All 3 test boxes ran the cache copy of pup 1.3.0→1.5.0 with `source:"cache"`. So the
"ship runtime only via the bundled seed" constraint is lifted: the `updateManifestUrl` auto-pull works.
(Still bump the bundled seed opportunistically so a truly offline first-run is current.)
## ⭐ DESIGN PROPOSAL: AD-managed shared runtimes (Node + Python) — see PROPOSAL-shared-runtimes.md
The Node UAC/PATH pain above is a symptom of a bigger gap: **no one owns bridge runtimes.** Full write-up
in `PROPOSAL-shared-runtimes.md` (this repo). TL;DR of the recommendation (a hybrid, not either extreme):
- AD keeps a shared, **content-addressed** portable-runtime cache (`…\adom-runtimes\node-22.11.0\`,
`python-3.12.7\`), populated from portable zips into a **user dir — no installer, no UAC**. Ideally AD
**bundles** one Node (+ Python) so a fresh box has it with zero download.
- Bridges **DECLARE** their runtime in `bridge.json` (`runtime: {kind, version, preferred}`) — they do NOT
install it. pup ships this declaration as of v1.6.1. Shared interpreter when compatible; a pinned version
fetched only when a bridge needs an odd one (no duplication for the common case).
- **AD spawns bridges by the interpreter's ABSOLUTE PATH** (`…\adom-runtimes\node-22.11.0\node.exe
server.js`). This is the linchpin — it kills BOTH the UAC (portable/user-dir) AND the stale-PATH dead-end
(no reliance on the machine PATH) at once. Python bridges get a per-bridge venv on the shared interpreter.
This replaces the per-bridge "roll your own Node" pattern (today's status quo, and the thing that caused
this whole debugging session). `desktop_install_node`'s UAC MSI becomes a last-resort fallback.