Pup - Puppeteer Bridge
Public Made by Adomby adom
pup is the AI's own browser: a real, full Chrome on the user's desktop that the AI fully controls (a sandbox, not the user's signed-in browser). Rides Bridge; pup_* verbs open windows and tabs, navigate, screenshot, and eval JS.
Recording and high-FPS windows
Sub-readme of the pup bridge README. Covers background video recording, the
highFpswindow mode, the lease that keeps it from flattening a battery, and how an AI negotiates for the time it actually needs.
The problem this solves
Chrome throttles a window that is occluded (covered by other windows) or backgrounded. It stops painting, freezes timers, and drops requestAnimationFrame. That is why your laptop sleeps fine with twenty Chrome tabs open, and it is correct behaviour.
It is also fatal to background video recording. pup windows are backgrounded by design (pup never steals your screen), so recording one through Chrome's normal power behaviour produces a 1-2 fps video.
pup used to solve that by launching every window with all four of Chrome's power-saving mechanisms disabled:
--disable-renderer-backgrounding keep rendering in a background tab
--disable-backgrounding-occluded-windows keep rendering when the window is occluded
--disable-background-timer-throttling keep timers/rAF firing
--disable-features=CalculateNativeWinOcclusion skip occlusion detection entirely
That made recording work and made every other window a battery hazard. A window in this mode can never idle down. Three idle pup windows held a Modern Standby laptop out of deep idle overnight, drew ~13 W, and drained it from 99.9% to 2.5% in about 5.5 hours (wiki issue #14). Nothing looked wrong on screen because the windows had no visible presence at all.
What pup does now
Default: Chrome's own power behaviour. A normal pup window throttles when occluded and costs essentially nothing sitting in the background. This is the right mode for driving, scraping, screenshots, and everything that is not video.
Opt in for recording: highFps: true.
pup_open_window { "sessionId":"demo", "url":"https://...", "highFps": true }
That window renders at full rate even while occluded, so a background take is smooth. Because it can never idle down, it is leased, not open-ended.
The lease
| Default lease | 20 minutes |
| Maximum lease | 120 minutes |
| Warning | logged ~2 minutes before the lease lapses |
| On lapse | the window is downgraded, not closed |
Why 20 minutes: long enough for a real demo take, short enough that a window someone forgot about cannot cost a battery overnight. The incident that motivated this ran for two days.
Downgrade means downgrade. When a lease lapses, pup relaunches the same session with the same tabs under normal power behaviour. Your window and its content survive; only the power profile changes. pup does not close a window that may be holding the user's work.
You cannot be cut off mid-recording
This is the guarantee that makes the lease safe. While a recording is actually running, the lease cannot lapse. pup keeps pushing it out for as long as frames are being pulled.
This is knowable rather than guessed, because recording runs through pup's own verbs
(pup_record_start / pup_record_stop), so pup has authoritative state, not a heuristic.
The activity signals, in priority order:
- An active recording — authoritative, holds the lease open indefinitely.
- Verb activity — any
pup_*call against the session shows it is in use. - An explicit extension —
pup_highfps_extend, for when you know up front you need longer but will not be recording the whole time.
Negotiating
pup tells you the lease terms in the _hint of every pup_open_window response, including
when it will downgrade and how to keep it. If you need longer:
pup_highfps_extend { "sessionId":"demo", "minutes": 45 }
You do not need to keep extending during a take. Extend when you are staging a long session that has gaps between recordings.
Recording a normal window
You can, and pup will not stop you, but if the window is occluded the take will be ~1-2 fps. pup logs a warning when a recording starts on a normal-power window so a bad video is not a surprise:
[highfps] "demo" recording started on a NORMAL-power window — frames will drop to ~1-2 fps
while it is occluded. Reopen with pup_open_window {highFps:true} for a
full-rate background take.
If the window is genuinely visible on screen for the whole take, a normal window is fine.
Checking state
pup_open_window returns a highFps field: false for a normal window, or
{active, minutes, expiresAt, msRemaining, recordingActive} for a leased one. The same shape comes
back from pup_highfps_extend.
Rules of thumb
- Driving, scraping, screenshots, waiting? Normal window. Never ask for
highFps. - Recording a window the user is NOT looking at?
highFps: true. - Recording something on screen the whole time? Normal window is fine.
- Long session with gaps between takes?
highFps: trueplus an extension sized to the session. - Done recording? Nothing to do. Stop the recording and the lease lapses on its own, and the window quietly returns to normal power.
# Recording and high-FPS windows
> Sub-readme of the [pup bridge README](README.md). Covers background video recording, the
> `highFps` window mode, the lease that keeps it from flattening a battery, and how an AI
> negotiates for the time it actually needs.
## The problem this solves
Chrome throttles a window that is **occluded** (covered by other windows) or backgrounded. It
stops painting, freezes timers, and drops requestAnimationFrame. That is why your laptop sleeps
fine with twenty Chrome tabs open, and it is correct behaviour.
It is also fatal to background video recording. pup windows are backgrounded **by design** (pup
never steals your screen), so recording one through Chrome's normal power behaviour produces a
**1-2 fps** video.
pup used to solve that by launching **every** window with all four of Chrome's power-saving
mechanisms disabled:
```
--disable-renderer-backgrounding keep rendering in a background tab
--disable-backgrounding-occluded-windows keep rendering when the window is occluded
--disable-background-timer-throttling keep timers/rAF firing
--disable-features=CalculateNativeWinOcclusion skip occlusion detection entirely
```
That made recording work and made every other window a battery hazard. A window in this mode can
never idle down. Three idle pup windows held a Modern Standby laptop out of deep idle overnight,
drew ~13 W, and drained it from 99.9% to 2.5% in about 5.5 hours (wiki issue #14). Nothing looked
wrong on screen because the windows had no visible presence at all.
## What pup does now
**Default: Chrome's own power behaviour.** A normal pup window throttles when occluded and costs
essentially nothing sitting in the background. This is the right mode for driving, scraping,
screenshots, and everything that is not video.
**Opt in for recording: `highFps: true`.**
```jsonc
pup_open_window { "sessionId":"demo", "url":"https://...", "highFps": true }
```
That window renders at full rate even while occluded, so a background take is smooth. Because it
can never idle down, it is **leased**, not open-ended.
## The lease
| | |
|---|---|
| Default lease | **20 minutes** |
| Maximum lease | **120 minutes** |
| Warning | logged ~**2 minutes** before the lease lapses |
| On lapse | the window is **downgraded**, not closed |
Why 20 minutes: long enough for a real demo take, short enough that a window someone forgot about
cannot cost a battery overnight. The incident that motivated this ran for **two days**.
**Downgrade means downgrade.** When a lease lapses, pup relaunches the same session with the same
tabs under normal power behaviour. Your window and its content survive; only the power profile
changes. pup does not close a window that may be holding the user's work.
## You cannot be cut off mid-recording
This is the guarantee that makes the lease safe. **While a recording is actually running, the lease
cannot lapse.** pup keeps pushing it out for as long as frames are being pulled.
This is knowable rather than guessed, because recording runs through pup's own verbs
(`pup_record_start` / `pup_record_stop`), so pup has authoritative state, not a heuristic.
The activity signals, in priority order:
1. **An active recording** — authoritative, holds the lease open indefinitely.
2. **Verb activity** — any `pup_*` call against the session shows it is in use.
3. **An explicit extension** — `pup_highfps_extend`, for when you know up front you need
longer but will not be recording the whole time.
## Negotiating
pup tells you the lease terms in the `_hint` of every `pup_open_window` response, including
when it will downgrade and how to keep it. If you need longer:
```jsonc
pup_highfps_extend { "sessionId":"demo", "minutes": 45 }
```
You do **not** need to keep extending during a take. Extend when you are staging a long session
that has gaps between recordings.
## Recording a normal window
You can, and pup will not stop you, but if the window is occluded the take will be ~1-2 fps. pup
logs a warning when a recording starts on a normal-power window so a bad video is not a surprise:
```
[highfps] "demo" recording started on a NORMAL-power window — frames will drop to ~1-2 fps
while it is occluded. Reopen with pup_open_window {highFps:true} for a
full-rate background take.
```
If the window is genuinely visible on screen for the whole take, a normal window is fine.
## Checking state
`pup_open_window` returns a `highFps` field: `false` for a normal window, or
`{active, minutes, expiresAt, msRemaining, recordingActive}` for a leased one. The same shape comes
back from `pup_highfps_extend`.
## Rules of thumb
- **Driving, scraping, screenshots, waiting?** Normal window. Never ask for `highFps`.
- **Recording a window the user is NOT looking at?** `highFps: true`.
- **Recording something on screen the whole time?** Normal window is fine.
- **Long session with gaps between takes?** `highFps: true` plus an extension sized to the session.
- **Done recording?** Nothing to do. Stop the recording and the lease lapses on its own, and the
window quietly returns to normal power.