Skip to content

feat(browser): a browser nobody is using rests - #65

Merged
httpsphl merged 3 commits into
mainfrom
feat/browser-rest
Sep 30, 2026
Merged

httpsphl merged 3 commits into
mainfrom
feat/browser-rest

Conversation

@httpsphl

Copy link
Copy Markdown
Owner

Stacked on #62 (tabs), which is stacked on #53 (the page filling the panel): until those merge, this diff shows their commits too. The two commits of this PR are the last two.

Why

A bot's Edge kept working after the bot was done with it. Measured with Edge 154 on a page with a busy timer and an animation:

CPU (of one core) RAM
open, nobody watching 84% ~450 MB, 7 to 10 processes
open, panel watching 126%
resting (this PR) under 1% the same

And it only closed after 10 minutes with the panel shut. With the panel open it never closed, and the panel opens by itself.

What

  • It rests the moment the bot's turn ends (its state leaves busy and needs_approval). The daemon takes a picture of the active tab, so the panel has something to show, and minimizes Edge's window (Browser.setWindowBounds). The window was never on screen, but for Edge it exists, and its pages now count as hidden: timers, animations and frames stop, as in any window someone minimized. Nothing is lost: tabs, forms and sessions stay as they were.
  • It wakes at once for the bot's next browser_* tool, when the owner takes control and when they reload. After the owner used it with the bot out of a turn, it rests again by itself (20 s without use, checked every 30 s).
  • It never rests in the middle of a tool or in the owner's hands.
  • Closing no longer waits for nobody to be watching. It closes after idle_minutes (10) without use, where use is a tool of the bot or something the owner did with the browser in their hands. In the owner's hands it does not close.
  • BrowserState.resting, and the panel shows "Resting" in place of "Live", with a hint that it costs the computer nothing and wakes when needed. The header's browser button no longer says the bot is using a browser that rests. Texts in en, pt-BR and es.
  • Spec 21.2, 21.7, 21.8, 21.9, 21.11 (N3.3) and the measurements in section 19.

What was tried and dropped

  • Page.setWebLifecycleState with frozen stops the page too, but back to active it stayed hidden and slow, and a Page.bringToFront after that hung Runtime.evaluate.
  • Emulation.setCPUThrottlingRate used more CPU, not less.
  • Closing the browser when the turn ends would free the memory as well, but loses the open tabs, what was typed in a form and logins kept only for the session, in the middle of a conversation with the bot.

What it does not do

Memory stays in use while the browser rests (about 450 MB each, up to max_open = 4) until it closes for lack of use. idle_minutes is still 10; lowering it is a one-line change if that is the wish.

Tests

  • crates/botloftd/tests/browser_rest.rs, with the real Edge and a fake bot's turn: the browser rests when the turn ends, a connection that starts watching then gets the picture, the bot's next tool wakes it with the page having been hidden once and nothing lost, frames come again, the owner's hands wake it and keep it from resting, and a reload wakes it.
  • Unit tests for what the sweep does (stay, rest, close) and for which bot states count as working.
  • browser.test.tsx with FakeBotloft: the "Resting" label and its hint, the header button, and taking control waking it.
  • cargo fmt, clippy -D warnings, cargo test --workspace and pnpm check pass. The daemon's suite ran 6 times in a row.
  • Seen in the dev preview (pnpm dev): Analyst's browser rests.

Still to see with real Claude Code

With a real bot on a page that moves (a video site, a dashboard), after its answer: the panel says "Resting" and Task Manager shows its msedge.exe processes near 0% CPU. Then ask the bot to go on in the same page: it wakes and continues without opening the page again.

A bot's Edge kept working after the bot was done: a page with a timer and
an animation took 84% of a core with nobody watching, and it only closed
after 10 minutes with the panel shut, never with it open.

Now the browser rests the moment the bot's turn ends (its state leaves
`busy` and `needs_approval`): the daemon takes a picture of the active
tab, for the panel, and minimizes Edge's window. The pages count as
hidden, so timers, animations and frames stop, as in any minimized
window; the same page then takes under 1% of a core. Nothing in the pages
is lost. It wakes at once for the bot's next browser tool, for the
owner's hands and for a reload, and rests again by itself 20 s after the
owner used it while the bot is out of a turn. `BrowserState.resting`
tells the app.

Closing for lack of use no longer waits for nobody to be watching: the
panel opens by itself and kept the browser open for good. Use is a tool
of the bot or something the owner did with the browser in their hands,
and a browser in their hands does not close.

`Page.setWebLifecycleState` was tried first and does not work for this:
back to `active`, the page stayed hidden and slow. Spec 21.2, 21.7, 21.8,
21.9 and 21.11 (N3.3), and section 19 has the measurements.
In place of "Live" the panel shows "Resting", with a hint that it costs
the computer nothing and wakes when the bot or the owner needs it. The
browser button in the bot's header no longer says the bot is using a
browser that rests. The preview's Analyst has a resting browser.
docs/spec.md: the browser's profile line keeps both changes: resting (this branch) and deleting a bot, which also closes the browser and deletes its profile (#54).
@httpsphl
httpsphl enabled auto-merge September 30, 2026 17:23
@httpsphl httpsphl mentioned this pull request Sep 30, 2026
@httpsphl
httpsphl merged commit ce02c92 into main Sep 30, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant