---
name: pup-browser-control
description: >
  Drive a headless/throwaway Puppeteer (pup) Chrome window via Adom Desktop, for
  tasks that need no login or that you want to record cleanly without touching the
  user's real browser. Trigger words: pup, puppeteer browser, headless chrome,
  anonymous browser, browser_eval, browser_open_window, record a browser tab.
---

# Pup browser control

`browser_*` (alias `pup`) drives a **separate Puppeteer-launched Chrome** on the
user's desktop, orthogonal to their real browser. Use it when **no login is needed**
(public pages, anonymous renders) or when you want a clean window to record.

## Core verbs

```bash
adom-desktop browser_open_window '{"sessionId":"x","profile":"x","url":"https://..."}'
adom-desktop browser_navigate    '{"sessionId":"x","url":"..."}'
adom-desktop browser_eval        '{"sessionId":"x","expr":"document.title"}'
adom-desktop browser_wait        '{"sessionId":"x","ms":4000}'
adom-desktop browser_screenshot  '{"sessionId":"x"}'        # PNG saved locally on the CLI host (/tmp)
adom-desktop browser_record_start/_stop                     # CDP screencast (LOW fps, see below)
adom-desktop browser_close       '{"sessionId":"x"}'
```

Sessions are keyed by `sessionId`; reuse it across calls.

## Upload via DataTransfer (same trick as nbrowser)

Pup is sandboxed from the local file input, so inject the bytes. Base64 the file,
stream into `window.__b` in <40k chunks via `(window.__b += "<chunk>", window.__b.length)`
(comma op = single expression), then decode to a `File` and set the input via
`DataTransfer` + dispatch `change`. Verified getting JLCPCB to render a board ZIP
anonymously, no login.

## Recording a pup tab, read this first

- `browser_record_start` uses **CDP `Page.startScreencast`**, which is **low-fps, ugly
  JPEG**. For a polished demo, prefer whole-desktop `desktop_record_*` (see
  [screen-recording](../screen-recording/SKILL.md)) over this.
- CDP screencast is **paint-throttled** when the tab isn't OS-foreground. If you must use
  it, `browser_focus_window` (Win32 SetForegroundWindow) **before every action**, calling
  it once isn't enough; anything that grabs focus re-throttles it. Sniff-test:
  `frameCount / (durationMs/1000)` should be near your requested fps; below ~12 fps means
  the window lost foreground.

## When to choose pup vs the real browser

- **No login needed / want it clean / don't touch the user's session** -> pup.
- **Needs the user's cookies/logins, or you'll push it to checkout** -> the real browser
  via [native-browser-control](../native-browser-control/SKILL.md).
- Common combo: anonymous board render/price in pup, the full logged-in order in nbrowser.
