Download

pup: the Puppeteer bridge

pup is the AI's own browser: a real, full Chrome/Edge window on the user's desktop that the AI drives with complete programmatic control, but a sandbox. It runs in a fresh, isolated profile that is never the user's real signed-in browser, and opens in the background by default so it never disrupts them. That trade is exactly why pup exists alongside nb / nbe (the native browser and its extension): nb/nbe drive the user's real browser, their cookies, SSO, saved logins, their identity, for when a task needs to BE the user. pup is the opposite trade: no borrowed identity, but total control, a real, disposable browser the AI owns end to end (open/close windows + tabs, navigate, screenshot, eval JS, record). Logged out by design, it's the safe, fully-drivable default for automation, testing, scraping public pages, and showing wiki pages; reach for nb/nbe only when you genuinely need the user's real logins. pup drives Chrome for Testing, the automation build (why: docs/WHY-CFT.md); pup installs and maintains it by itself, with the machine's installed Chrome/Edge as fallbacks.

The core goal: an AI-driven browser that can do everything it needs to for you - the best assistant in the world. By default every pup window surfs on the shared durable adom-you profile, and every login made there enriches a shared credential store. Over time that store lets pup automatically enter usernames and passwords on every site it has ever seen, which is what makes a truly self-sufficient AI browser possible. Isolated throwaway profiles exist for the cases that need them (logged-out testing, acting as another user), but they build nothing: adom-you is the default on purpose.

pup drives Chrome for Testing (CfT), the build Google ships for automation. Branded Chrome fights automation in ways that matter here: the "controlled by automated test software" banner blips over the window during real driving and cannot be suppressed, and Chrome 137 removed every silent way to load pup's toolbar extension. CfT has none of those fights, pins a deterministic version, and lets the Adom Pup toolbar ride every launch as a flag. The full technical record, including what we tried and verified on branded Chrome, is in docs/WHY-CFT.md.

To drive the user's real, signed-in Chrome/Edge (their cookies, SSO, saved logins), that's the Adom browser extension's nbrowser_* verbs, a separate bridge, not pup.

Canonical page: https://wiki.adom.inc/adom/pup-bridge

Install vs Download, which is which (and why the version numbers differ)

The page header shows two things, for two different places. Most people need only the first.

On the page What it is Who runs it You usually…
Install, adom-wiki pkg install … The AI skill pack, the pup skills that teach a cloud/container AI how to drive the bridge. Docs only, no runtime; drops into ~/.claude/skills + ~/.codex/skills. your container / cloud AI run this (or it arrives via sync_skills)
Download for your machine, adom-bridge-puppeteer-v<ver>.zip The bridge runtime, the actual Node program (browser detection + driving) that runs on the desktop. Bridge, on the user's PC do nothing, Bridge auto-installs & auto-updates it; the manual download is only for offline/manual installs

Why two different version numbers? They're independent artifacts. The Install (pkg) version bumps whenever the skills/docs change (often). The Download (runtime) version bumps only when the bridge code changes (rarely). So it's normal to see e.g. Install v1.8.27 and Download v1.8.20, nothing is out of sync; they just version on their own clocks.

(There's also a third copy, the runtime is bundled inside the Bridge installer as a first-run seed, superseded by a newer cache copy via updateManifestUrl. You never touch it directly.)

Use it

# everyday: open + screenshot. Opens in the BACKGROUND automatically, no need to lower it,
# and it's fully drivable/screenshottable while hidden, so the user is never interrupted.
adom-bridge-cli pup_open_window '{"sessionId":"myapp-web","owner":"myapp","url":"http://localhost:3000"}'
adom-bridge-cli pup_screenshot  '{"sessionId":"myapp-web"}'

# readiness (use pup_readiness, NOT pup_status). On a box with Chrome or Edge this is
# instantly {ready:true} with no download. Only a box with no Chromium at all fetches Chrome for
# Testing in the background, poll until ready, then open.
adom-bridge-cli pup_readiness '{}'      # → {ready:true, browserKind:"chrome"|"edge"|...}
  • Task-prefix your sessionId + pass owner, sessions are shared across every AI thread on the desktop; that lets pup protect your window from another thread navigating it away.
  • foreground:true is the only way to show a window, sizing/positioning does not foreground it.

Full everyday usage (tabs, recording, window ownership, cold-start playbook) is in the pup skill (SKILL.md).

Window-type taskbar icons: read a pup window at a glance

The pup window-type icon family

Every pup window's taskbar icon states what kind of thing it is showing. All five share the same drawing (the teal Adom tile carrying a solid browser window) and differ only in the window's content: a monochrome glyph on the 24x24 Adom house grid, per the brand icon law (single color, no gradients, no emoji):

Icon Window content Means
wiki open book Adom wiki, public view: logged out, what the world sees
wiki signed in book + person Adom wiki, signed in: the user's logged-in view (private source, drafts, owner cards)
adom app the Adom mark An Adom app: localhost or a cloud-slug proxy URL
web globe The web: any other site (ti.com, digikey, ...)
mixed two panes Mixed: the window's tabs span more than one category
  • The category is derived from all tabs in the window; it updates live (add a digikey tab to a wiki window and the icon flips to mixed within about a second).
  • The overlay badge riding the icon's corner is separate and sacred: it is the active tab's own favicon, so you always see which site you are looking at. In grouped-taskbar mode it shows window/tab counters instead.
  • The tab title carries the same login signal in text: a solid dot (● Logged in) or hollow dot (○ Public) leads the title of every Adom wiki tab.
  • Under the hood, each window's identity (icon, name, Alt-Tab entry) rides a per-session Windows AppUserModelID that carries the category: the only way Win11 allows a taskbar tile to change live. Grouped mode instead keeps one stable, pinnable Adom.Pup identity.

Using pup's icons in your own tool (HD browser picker, launchers, menus)

If you are building a surface that offers "open a pup window" (a browser picker, a launcher tile, a menu item), use pup's real icon, not a stand-in. The canonical, self-describing asset set lives in the wiki repo at assets/pup-icons/, in three formats:

  • SVG (pup-cat-*.svg), scalable, the right choice for a web/Tauri picker.
  • PNG (pup-cat-*-{32,48,128,256,512}.png), raster fallback / retina.
  • ICO (pup-cat-*.ico), Windows multi-size, for taskbar/shortcut contexts (256px frame is PNG-compressed, per the Vista+ rule, so it never renders as a generic document).

For a launcher/picker item, use pup-cat-default, the neutral teal browser-window tile. It is what a pup window's taskbar button looks like before its content is known, so the picker previews the real result. The five category icons above (wiki, wiki-in, app, web, mixed) are for showing an existing window's kind, not for a generic "open pup" action.

Fetch any asset from the wiki without cloning:

https://wiki.adom.inc/api/v1/pages/pup-bridge/files/assets/pup-icons/pup-cat-default.svg
https://wiki.adom.inc/api/v1/pages/pup-bridge/files/assets/pup-icons/manifest.json

assets/pup-icons/manifest.json is machine-readable: it maps each icon id to its meaning, its glyph, and its file in every format, and names recommended_for_launcher so a tool can pick the right one programmatically. Brand rule if you ever redraw one: teal tile #00b8b0 + dark-teal window body #003d40 + a single-color teal glyph, no gradients, shadows, or emoji.

Real windows, one per type

Full windows as pup opens them (title bar, tabs, page). Note the tab title glyphs on the wiki pair and the signed-in header on the second:

Adom wiki, PUBLIC (tab: ○ Public, page header shows Login):

A pup window on the Adom wiki, public view

Adom wiki, SIGNED IN (tab: ● Logged in, page header shows the user's name):

A pup window on the Adom wiki, signed in

An Adom app (here: the shotlog viewer on a cloud slug URL):

A pup window on an Adom app

The web (ti.com):

A pup window on the open web

Mixed (a digikey tab and a wiki tab in one window):

A pup window with mixed content

Overlay badges: the corner of the taskbar icon

The overlay badges pup places on its taskbar icons

The base icon states the window TYPE; the small overlay riding its lower-right corner carries LIVE detail, composited exactly like this:

Overlay When What it tells you
the active tab's favicon on a dark rounded plate split mode, page serves a favicon which site the active tab is on, at a glance
a count badge (white digit, dark plate) split mode, 2+ tabs and no favicon how many tabs the window holds
the dual counter (dark = windows, teal = total tabs) grouped mode how much is stacked under the single Adom Pup button

The overlay never carries branding or state that belongs to the base icon: it is live per-window detail only, and the favicon always wins the slot when one exists.

The Adom wiki: logged-in vs public view, and the taskbar toggle

pup can show any Adom wiki page from two viewpoints, and both the AI and the user can switch:

  • Public (default): a fresh logged-out profile: exactly what the world sees. Use it to verify what a publish actually exposed.
  • Signed in: pup_open_window {..., wikiView:"authed"} routes to a reserved persistent profile whose cookie jar holds the user's ~30-day SSO session. One login serves every AI thread on the machine. First use returns wikiLoginNeeded:true; the user signs in once, in that window.

The user can flip a wiki window themselves: right-click its taskbar button: the jump list carries "Adom wiki: switch to logged-in view" (or "...switch to public view"). Clicking it relaunches that same window under the other cookie jar, brings it to the front, and shows an on-screen caption while it works ("Switching to the logged-in view of the Adom wiki", then "Adom wiki: now the LOGGED-IN view (Their Name)"). The AI-side equivalent is the pup_wiki_set_view verb, which exists for that jump-list click: AI threads should pass wikiView on open instead.

One session, one OS window

Every pup session gets its own OS window, even when sessions share a browser profile (as all signed-in wiki windows share the authed cookie jar). This is what makes per-window identity possible: a window's title belongs to its active tab, so windows that share sessions as tabs cannot be found, branded, flashed, or given jump lists individually. Sharing a profile shares the cookies; it never merges windows.

Recording

pup can record what it drives, a single tab/window or the whole desktop, straight from the cloud, with no HUD and no need to bring the window forward.

Example pup recording, driving the Adom wiki, captured in the background

Above: a GIF preview of a real pup_record capture (≈8.6 s, the tab navigating the Adom wiki, recorded in the background on a VM). The native capture is the WebM linked below, this GIF is just an inline preview.

High-FPS windows: recording something the user is not looking at

pup windows are backgrounded by design, and Chrome throttles a window that is occluded, so recording one normally yields a 1-2 fps video. pup can disable Chrome's power-saving to keep a window painting at full rate, but a window in that mode can never idle down (three of them once drained a laptop overnight, wiki issue #14).

So it is opt-in and leased:

  • Default is Chrome's own power behaviour. Normal windows throttle when occluded and cost nothing in the background. Right for driving, scraping and screenshots.
  • pup_open_window {highFps:true} renders at full rate while occluded, for background recording. It holds a lease (default 20 min), and an active recording holds that lease open indefinitely, so a take is never cut off. On lapse the window is downgraded back to normal power by relaunching with its tabs intact, never closed.
  • pup_highfps_extend {sessionId, minutes} negotiates more time up front.

Full details, defaults, activity signals, and rules of thumb: RECORDING.md.

Two recorders, pick by what you're capturing

Verb pair Captures How it works under the hood
pup_record_start / pup_record_stop ONE pup tab/window, the page content CDP Page.startScreencast (JPEG frames, up to ~50 fps) piped to ffmpeg, encoded to VP9 in real time → one .webm. Tab-scoped at the protocol level, so it captures the exact tab even in the background, no getDisplayMedia, no picker, no foreground.
desktop_record_start / desktop_record_stop the WHOLE desktop (multiple apps, dialogs) Screen capture via MediaRecorder → one .webm; ffmpeg remuxes it to stamp a proper Duration.
adom-bridge-cli pup_record_start '{"sessionId":"demo-web"}'          # → { recordingId }
# ...drive the scene: navigate, click, type, scroll...
adom-bridge-cli pup_record_stop  '{"sessionId":"demo-web","recordingId":"<id>"}'   # → { path: "...webm" }

ffmpeg is required for recording. The bridge auto-detects it (a WinGet Gyan.FFmpeg install, PATH, or common dirs) and re-checks lazily on record_start, so if it's missing you can winget install Gyan.FFmpeg and just retry, no bridge restart. pup_record_status / pup_record_list (and the desktop_record_* equivalents) report in-flight and finished captures.

Formats, one native format, easy conversion

pup records to one format natively: WebM (VP9), for both recorders. It doesn't offer a format switch; instead, convert with the bundled ffmpeg when you need MP4 or GIF. Real numbers from the ≈8.6 s demo above (1264×705):

Format Codec Size How you get it Best for Watch out for
WebM (view) VP9 143 KB pup's native output, no step Chrome/Edge/Firefox, small + high quality, the source of truth Older Safari, PowerPoint, and some chat apps don't accept VP9/WebM
MP4 (view) H.264 135 KB transcode (below) Universal, Safari, iOS, PowerPoint, Slack/Teams, "send it to anyone" H.264 needs even width & height, odd dims (like 705) fail at frame 0; the scale filter forces even
GIF (view) , 192 KB transcode (below) Auto-playing, looping inline preview in any README/chat/GitHub, no player, no click (like the one above) No audio, capped colors, and it balloons fast at higher fps/resolution/length, keep it short + downscaled
# → MP4 (H.264, universal). The scale filter forces EVEN dimensions (H.264 rejects odd w/h → frame 0).
ffmpeg -i rec.webm -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -c:v libx264 -crf 23 -pix_fmt yuv420p -movflags +faststart rec.mp4

# → GIF (silent, looping inline preview). Palette pass keeps colors clean; drop fps/scale to shrink.
ffmpeg -i rec.webm -vf "fps=12,scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" rec.gif

Rule of thumb: keep WebM for archiving + web embeds; make an MP4 the moment a human on Safari/ PowerPoint/phone needs it; make a short GIF only for an inline auto-play preview.

Source & development

This bridge is cloud-owned here (extracted from adom-bridge/plugins/puppeteer, mirroring the kicad/fusion bridges). Bridge ships a bundled seed and auto-pulls newer versions from this page.

  • Clone the source: adom-wiki repo clone adom/pup-bridge
  • Runtime lives in src/ (server.js, chrome.js, bridge.json, …); the release zip is src/ at zip-root.
  • Maintainer skills (pup-bridge-dev, pup-bridge-publish) are source-only, in dev-skills/ + publish-skills/, not shipped in the pkg (per the Bridge SDK a pkg ships only user skills). Skill map:
Skill Ships in pkg? What it's for
pup (root SKILL.md) ✅ user Start here, mental model (CDP-launched fresh process of the installed browser, rendered-but-backgrounded), when-vs-extension, quick start
pup-windows-sessions-tabs ✅ user sessionIds, window ownership (don't steal another thread's window), background-vs-foreground, many tabs in one window
pup-screenshots-recording ✅ user Screenshots (full-page/full-res) + recording; driving/verifying tricky pages (shadow DOM, nested scroll)
pup-browsers-and-chrome ✅ user Browser detection/launch, pup_use, installing Chrome/CfT (incl. UAC-notify), readiness, cold-start errors
pup-adom-wiki ✅ user Driving + verifying wiki.adom.inc pages in pup (view/screenshot/verify; the login situation)
pup-bridge-dev / pup-bridge-publish ❌ source-only MAINTAINERS: bridge internals + the publish/release recipe (in dev-skills//publish-skills/, not shipped)
  • Ownership boundary: CLAUDE.md. Publish recipe: PUBLISHING.md. History: CHANGELOG.md.

Extend pup, add your own pup skill (third parties)

Built a skill that drives pup for a specific job (a site-specific scraper, a visual test flow, a domain widget)? You don't need write access here, surface it from this page with a breadcrumb:

  1. Publish your skill to your own wiki page (see the adom-wiki / wiki-skillpack skills). Make it a normal user skill so pkg install drops it into a container's ~/.claude/skills.
  2. Drop a breadcrumb on this page pointing at it:
    adom-wiki breadcrumb post adom/pup-bridge \
      --label "Your skill name, one-line what it does" \
      --target-url "https://wiki.adom.inc/<owner>/<your-slug>" \
      --category "skill"
    
    It's pending until the page owner approves it, then it shows in this page's Breadcrumbs tab.
  3. Discovery is automatic: an agent working with pup can list related third-party skills with adom-wiki breadcrumb list adom/pup-bridge, approved breadcrumbs are how pup finds community skills that build on it.

Keep breadcrumbs on-topic (they genuinely extend pup / browser-driving); off-topic ones get rejected.

MIT licensed.