bro / browser
AGENTS.md12 starsChanged 13 days agoApache-2.0View on GitHub
The bro-browser member publishes the browser persona and its page reader, the registered webview worker type, its owner and setup commands, and its container-side daemon and capture process. It depends on core for broker and artifact contracts, on bro-ride for setup's foreground worker run, and on the MCP SDK for the Playwright stdio client. Only bro.webview.setup imports ride; the persona declaration, registered type, and mounted toolsets stay dependency-light because every launch-scope fold and broker root loads them. Formatting, linting, typing,…
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- AGENTS.mdAGENTS.md
- bench/AGENTS.mdAGENTS.md
- benchmark/AGENTS.mdAGENTS.md
- bro/AGENTS.mdAGENTS.md
- dev/AGENTS.mdAGENTS.md
- filetypes/AGENTS.mdAGENTS.md
- local/AGENTS.mdAGENTS.md
- oops/AGENTS.mdAGENTS.md
- ride/AGENTS.mdAGENTS.md
The file
We split this AGENTS.md into the rules it gives an agent
3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 5
Only bro.webview.setup imports ride.
- Very specific: line 12
Run sync-scripts --project browser after adding or removing a CLI, and build the wheel with uv build --package bro-browser.
- Very specific: line 76
Every read is bounded at the profile limit plus 1 KiB, and capture's child processes stay off its stdout, which carries only this sequence: …
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Browser
The bro-browser member publishes the browser persona and its page reader, the registered webview worker type, its owner and setup commands, and its container-side daemon and capture process.
It depends on core for broker and artifact contracts, on bro-ride for setup's foreground worker run, and on the MCP SDK for the Playwright stdio client.
Only bro.webview.setup imports ride;
the persona declaration, registered type, and mounted toolsets stay dependency-light because every launch-scope fold and broker root loads them.
Development
Formatting, linting, typing, tests, and packaging use the root repository gate.
The host-only real-browser route runs separately with run-tests --only webview_e2e.
Run sync-scripts --project browser after adding or removing a CLI, and build the wheel with uv build --package bro-browser.
Components
bro/webview/worker.py— the dependency-light registered type, its option declaration and wire mapping, and packaged container specification.bro/webview/profile.py— the profile bound, envelope validation, and profile-version to Playwright MCP pin pairingbro/webview/container/Dockerfile— the runtime-derived image with Xvfb, noVNC, Chromium, and the pinned Playwright MCPbro/webview/serve.py— the shared display, VNC, and Playwright startup plus the container daemon, passed-profile loader, and command loopbro/webview/capture_protocol.py— the options environment name and bounded exchange-line size shared by setup and capturebro/webview/capture.py— the container-side capture exchange and fixed storage-state callbro/webview/setup.py— the host-side profile lock, seed and capture workflow, guarded store write, and summarybro/webview/cli.py(webview) — the owner-sideopen,close, andsetupverbs and the container-sideserveandcaptureverbsbro/webview/mcp.py— the registeredwebviewtoolset for typed owner-side open, command, live-roster, sharing, reopen, and close operationsbros/browser/browser.py— the registered browser persona, its webview launch seed, bounded tool roster, policy, and reporting contractbros/browser/mcp.py—browser::look, the focused snapshot, text, and artifact reader with checked element refsbros/browser/scenarios.md— thebrowser-scenariosman page (declared inreferences.py) for personas that summon the browser: profile grants, signing in withwebview setup, persistence, remote views, and downloadsbros/browser/spells/browse.md— the owner-led instruction loop, clarification threads, uploads, and session log
Browser persona
browser is the semantic interface to webview missions.
Its own seed grants the whole webview worker type, while profile selection, a visible view, and page downloads require the guarded webview.cred, webview.vnc, and webview.downloads permissions.
It mounts webview::, browser::, and artifact::, withholds Claude's file, shell, delegation, and web tools, and closes a webview before answering a one-shot request.
Its answers omit element refs, page markup such as snapshot syntax or HTML, and tool names;
Markdown formatting is allowed.
The [[browse]] spell keeps one webview open while the owner sends each instruction as a quest question;
a clarification is a counter-question in that thread, and "done" closes the webview and returns the session log.
browser::look captures a snapshot or the page's decoded innerText, or reads an existing artifact ref, and sends that representation plus one focused question to a disposable reader.
It returns a bounded answer and only element refs whose role and accessible name match the snapshot it read.
The optional mu credential enables the reader through its reader role and is the boundary across which page content travels;
without it the browser uses browser_find, targeted snapshots, and artifact::read or artifact::grep.
Owner toolset
The webview toolset is the typed owner surface over the mission wire.
open retains the launch options and initial shares, command bounds reply text while preserving the whole text by artifact ref, and tools condenses the live Playwright roster.
share returns the worker-side upload path, reopen repeats every retained option and share before restoring the last reported page URL, and close returns the terminal outcome.
Owner command
webview open forwards optional VNC, a requested VNC port, downloads, a cookies profile pass, origin allow and block lists, shared artifact refs, and a lifetime bound to launch,
then waits through the accepted and started marks for the daemon's ready event.
--cookies <instance> passes that profile without putting it in the owner's store;
--vnc --port <port> fixes the noVNC view's launcher-loopback port.
It prints the mission id and optional noVNC URL as JSON;
a denial, failed launch, or startup silence exits non-zero, with startup expiry cancelling the launch.
webview close MISSION asks the daemon to close, then waits for its acknowledgement, terminal outcome, and settled worker supervision.
webview setup <instance> runs only on a host terminal, opens a foreground capture container and prints its noVNC URL, then stores the state after Enter under cookies+<instance>.
It seeds an existing profile unless --fresh, keeps IndexedDB when the seed contains it or --indexed-db requests it, and accepts --url and a fixed --port.
It holds the stored name's lock for the run, writes only while the starting material is unchanged, and reports counts and bytes without values.
Commands between open and close use mission ask <id> '<json>' --wait, with mission history <id> retaining their full payloads.
mission share <id> <ref> makes a later-minted upload available under /workspace/artifacts/<ref> without reopening the webview.
Browser profile
The daemon reads the selected cookies kind before it listens and refuses an oversized, malformed, extra-kind, or newer-version profile without exposing its material.
It strips profile_version, writes the Playwright storage state at 0600 in its private configuration directory, and starts Playwright MCP with --isolated --storage-state <path>.
The file remains for the daemon's life so a re-created isolated context starts from the same profile.
The Playwright MCP storage capability and browser_run_code_unsafe remain withheld.
Capture wire
Setup starts capture with WEBVIEW_CAPTURE_OPTIONS={"url", "indexed_db"} and exchanges ASCII-escaped JSON objects one per line over its stdin and stdout.
Every read is bounded at the profile limit plus 1 KiB, and capture's child processes stay off its stdout, which carries only this sequence:
setup sends {"seed": <state>|null}, capture sends {"event":"ready"}, setup sends {"request":"state"}, and capture sends either {"event":"state","state":<state>} or {"event":"error","error":<reason>}.
Capture runs the display, noVNC, and Playwright startup shared with serve in a private temporary directory and saves state through its fixed browser_run_code_unsafe call.
Mission wire
A webview mission has talk {owner.question, worker.say} and carries JSON objects as its chat payloads.
An owner question is either one Playwright MCP call as {tool, arguments?} or {webview: tools|close}.
The daemon answers a tool call with {text, files}, where each file names its workspace-relative path and artifact ref or mint error, and answers a malformed or failed call with {error}.
An oversized reply names the artifact holding its text or its whole object instead.
The ready say is {event: ready, vnc}, and a close ends the mission with the number of successful tool calls.
The daemon mints the files a tool result names — link lines in its Result and Snapshot sections and download lines in its Events section — when the call wrote them anywhere under /workspace outside the read-only artifact view;
a named file the call did not write is reported as an error entry, and every other file the call wrote outside the output directory is removed unminted.
A finished download is named by the first reply after it finishes, so it is minted from the output directory whenever a reply names it, and unnamed files in the output directory are left in place.
named_files owns the result format, and serve_test.py pins it case by case, so a Playwright MCP bump that changes the layout fails there and in webview_e2e instead of silently dropping files.
It withholds every tool in WITHHELD_TOOLS from both the live roster and calls.
A webview mission has an empty base authority.
Image pin
The version on the npm install -g @playwright/mcp@… instruction in container/Dockerfile pins both the tool roster and Chromium dependency used by the image.
Bump it by editing that instruction and adding the new pin as the next profile version in profile.py's PLAYWRIGHT_MCP_PROFILE_VERSIONS;
webview_e2e loads a synthetic profile of every version the table holds.
Then run the webview unit tests and build bro-browser;
the Dockerfile content changes the worker image hash.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

