Bonnie
booting
·
0 tools
How it works
The phone
Your own machine
Full access is on.
Turn off
Warrant live
Revoke now
Your agent tests your web app on a phone. You watch it work.
Through WebMCP it opens the app, reads the screen and the console, finds what breaks, stages the fix and asks you before it writes. A Linux workbench inside this tab runs the app and keeps every log. How it works
Try it click a line to copy it, paste it to your agent
Test the app on the phone. Find what breaks on mobile.
Fix beacon. It crashes; stage the fix, ask before writing.
Open a live site. Read a real website on the phone.
Look around. What is on this machine?
Delete the old releases. Keep v1.1.0; ask for what you need.
Test the gate. Try to grant yourself a warrant.
No agent is attached to this browser.
Open this page in ChatGPT, or in Chrome with WebMCP. Everything below works by hand in the meantime.
collapse
gesture nav 3-button nav
Nothing open yet. Type a path or a URL above, or ask your agent.
· measured sizes
On the screen
Open the app from the workspace, or a website. What the agent reads with device_snapshot lands here: layout findings, in words.
Console
Activity 0
Nothing yet. Paste a line from above into your agent, or open something on the phone. Every tool call, grant and revoke lands here.
Workbench
starting a machine…
Log
Files
Changes
Screen
loading emulator…
Pick a file. A ◐ marks a staged edit that is not on disk yet.
No staged edits. When the agent stages one it appears here as a diff you can read, before anything touches disk.
The machine's own VGA text console, drawn by the emulator: what a monitor plugged into the box would show. The log you share with the agent is the serial line. Why two consoles
How it works Close
A Linux 4.16 kernel boots on an emulated x86 (v86, WebAssembly) inside this page: a shell, a filesystem, processes, a VGA console. It holds the workspace your app is served from, runs the commands the agent is allowed to run, and keeps the log. No server. It has no network, and it is erased when the tab closes.
The catalogue is generated from the machine
When a machine attaches it reports a capability manifest, and the WebMCP tool list is built from that. This box has no tmux, so there is no pane tool; no Codex, so no subagents. The page says which tools it did not register and why.
Lifetime is an AbortSignal
Every registration scope (always, session, view, warrant) is one AbortController passed to document.modelContext.registerTool(). Open the Changes tab of the workbench and changes_review exists; close it and the tool is gone. Watch the count in the header.
The warrant is the registration
Writing to disk and running commands unattended are not gated handlers. Those tools are absent until you click Grant, and grant() requires transient user activation, which a tool call never has. The page ships the attack as a tool, warrant_force_grant, so you can watch it fail.
Two consoles
The workbench log is the serial console (ttyS0); you and the agent type into the same shell. Unattended commands run on a second, unwatched shell (ttyS1). The Screen tab shows the VGA text console, where the kernel's own init shell lives.
Nothing leaves the browser
After boot the page makes no request to its own origin. The one exception is a website you open on the phone through the relay, which is fetched on this origin; a PerformanceObserver counts every request, the number is in the footer, and it is a tool the agent can call.
state booting
The phone is a real browsing context held at that phone's viewport, pixel ratio, safe areas and platform hints, drawn in its frame the way an installed web app is shown: the status bar overlays the page, as with viewport-fit=cover.
Not iOS or Android. No Apple or Google code runs here. What a web app can observe is what is simulated, because that is what a web app is tested against.
Apps load from the workbench's workspace with their CSS, scripts and SVGs inlined and env(safe-area-inset-*) replaced by the device's real insets, so a fix the agent commits on the Linux box is the fix on the phone. A live website goes through the relay on this origin so it can be read and tapped, never signed in; with the Bonnie Live extension it opens as the real site in your own browser, signed in as you; framed directly it is private and uninspectable.
Which phones, which browsers
Every iPhone ever made, from the original to the 17e, and the current Android references (Pixel 10, Galaxy S26, Z Flip 7, Z Fold 7): 60 models, generated from the vendored mobile-browser-chrome-devkit (2026-09-02) and cross-checked against its JSON by the suite. Any other phone: device_custom takes a width, height, pixel ratio, cutout archetype and navigation.
The phone is drawn from the kit's own vectors, composed in its layer order: the model's frame (svg/iphone-frames), the status bar, the browser chrome for the state (svg/browser-chrome, split at the separator the kit draws), the home indicator or Android navigation (svg/system-bars), the cutout archetype. Every height is the kit's; each state names the files it was drawn from in device_describe. The browser is state, as the kit describes it: an installed app; Safari 26 in its compact, bottom or top layout; Safari 18; Chrome with its address bar at the bottom or the top; controls expanded or collapsed; gesture or three-button navigation on Android. Each state changes the viewport and the safe areas the page gets. A second set of sizes, measured from screenshots of a real iPhone 16 Pro Max on iOS 26, is one click away under the phone.
device_geometry reads what the page measures for itself — viewport, pixel ratio, screen, display mode, pointer — and says whether it matches the fixture; device_matrix sweeps the page across every viewport size. Honest limits: resolution and colour-scheme media queries inside the page follow the host browser, not the phone; a real WebKit or Blink is not running.
Bonnie Live is a small companion extension. With it, a URL you open on the phone is the real, published site in your own browser, signed in as you : no proxy, no second browser, nothing leaving this machine. Without it, a site goes through the relay on this origin: readable and tappable, but never signed in.
Turn it on
Open chrome://extensions (the same page works in ChatGPT Atlas).
Turn on Developer mode .
Click Load unpacked and choose the webmcp/extension folder from the repository.
Reload this page. The phone bar reads Bonnie Live is on .
What it does, and only here
It acts inside this tab alone: it lets the site be framed, gives its requests the phone's user agent, keeps the site's cookies in a jar of its own (a cross-site frame can neither store nor send them), and injects the phone's shim and reading tools into every page the frame commits. Its rules are session rules and die with the tab.
Honest limits
The engine is your browser's, not a phone's. A site's own scripted requests in the instant after a login are not gated, only navigations are. Chromium only for now.
The workbench above is disposable and lives in this tab. Bonnie's host runs on your real computer and pairs it to this page over a direct peer connection, with no relay and no account. Your agent then gets the same catalogue, generated from what that machine has: tmux terminals that outlive the tab, the real filesystem, the screen, Codex subagents.
git clone https://github.com/meshbergio/bonnie
cd bonnie && ./install.sh
bonnie pair # prints a URL and a QR code — open it in this page
Same gate Warranted tools do not exist until you grant them here, with a real click. A tool call cannot produce one.
Same record Every call, warrant and command lands in an append-only ledger the agent can read back, including what happened while it was not looking.
Nothing in the middle The page is static. Once paired it makes no requests to its own origin; the counter in the footer is the measurement.
Ask your agent for bonnie_install_plan and it will walk you through it.
An archive is the whole machine in one file: its memory and disk as the emulator saved them, plus the staged edits, the record, and what the phone had open. Resume it later and you are where you left off, including anything typed into the shell.
Authority does not survive a file. A live warrant or standing access is never archived and never restored; the agent starts a resumed session with exactly the tools it had at boot.
Drop a .bonnie archive here, or click to choose one
Download
Archive this session now
The agent can prepare an archive with session_archive, but the download needs your click. It can read what a loaded file contains with session_describe.