Releases: Don-Works/brw
Release list
brw v0.5.5
Full Changelog: v0.5.4...v0.5.5
brw v0.5.4
brw v0.5.3
brw v0.5.2 — extension-connection flap guard
brw v0.5.2 — extension-connection flap guard (fixes the flashing icon)
When two browser profiles run brw against the same bridge (e.g. Profile 1 and Profile 2 both have the extension enabled on the default port), the two extensions endlessly displaced each other — connected → "replaced by new extension connection" → disconnected, several times a second. That churn is the flashing brw icon, and it makes the bridge unusable.
- The bridge now detects the flap (≥5 connection replacements within 10s) and enters a hold: it keeps the live connection and rejects intruders (
StatusTryAgainLater) instead of replacing, extending the hold while collisions continue. A genuine single reconnect (MV3 service-worker restart, network blip) is unaffected — the hold only trips on rapid churn, and is bypassed the moment the live connection actually drops. - Result: the winning connection stays stable (icon steady), and the daemon logs an actionable hint naming the fix (disable brw in the other profile, or give it its own
--bridge-addr).
Regression test: TestExtensionFlapGuardRejectsColliding.
Full changelog: v0.5.1...v0.5.2
brw v0.5.1 — resilient no-tab_id resolution
brw v0.5.1 — resilient no-tab_id resolution (fixes a 20s latency cascade)
Fixes a regression from v0.5.0's default tab isolation: when a browser's extension stops answering open_tab — e.g. a real Chrome whose extension hasn't been reloaded to match the new daemon, or a transiently wedged extension — the isolation auto-open re-fired on every no-tab_id action and each hit the full 20s bridge timeout. This surfaced as brw__brw_evaluate 20003ms repeated across dozens of calls.
- The isolation auto-open is now bounded (8s per attempt) and cooled down (15s after a failure), so a wedged browser yields one fast, logged failure instead of a per-call 20s hang. brw stays responsive and logs an actionable hint ("reload the brw extension, or pass tab_id").
- No behavior change on a healthy browser — auto-open works as before.
Workaround on any version: pass an explicit tab_id to bypass auto-open entirely (resolves in ~30ms).
Full changelog: v0.5.0...v0.5.1
brw v0.5.0 — tab isolation by default + profile-daemon discovery
brw v0.5.0 — tab isolation by default + profile-daemon discovery
Multi-profile, agent-friendly browser control: brw now stays out of your way on a shared Chrome, and a gateway can discover every profile-daemon you run.
✨ Tab isolation is now the default (extension bridge)
A no-tab_id action now targets the tab brw owns, never the tab you're looking at. The first page action opens a fresh tab in brw's own group, in the background, instead of hijacking your current tab. Your existing tabs are touched only when you pass an explicit tab_id.
- Stops automation (and parallel agent runs) from stomping your open tabs.
- Restore the previous "follow my focused tab" behavior with
--bridge-follow-focus(orBRW_BRIDGE_FOLLOW_FOCUS=1).
🔎 brwctl daemons
New command that enumerates the extension-bridge profiles in your browser-profiles.json, probes each daemon's /health, and emits JSON (name, profile, workspace, http_addr, ws_addr, extension_id, reachable, identity). This is the discovery contract a gateway (e.g. MCPlexer) consumes to register one namespace per browser — the foundation for running several Chrome/Chromium profiles and letting an agent pick which one.
Notes
- Behavior change: the bridge default flipped from follow-focus to isolation. Interactive single-operator users who want brw to act on whatever tab they've selected should pass
--bridge-follow-focus. - The background-open part needs the updated extension (reload in
chrome://extensionsafter upgrading); the no-stomp/own-tab resolution works daemon-side regardless.
Full changelog: v0.4.1...v0.5.0
brw v0.4.1
What's Changed
- fix(brw): pin agent tab (stop drift to user/Chat tabs) + ship #6 downloads, #11 frames/window_bounds/typed-errors by @revitteth in #15
- fix(brw): honest include_frames (clickable cross-origin frames) + fix version test by @revitteth in #16
Full Changelog: v0.4.0...v0.4.1
brw v0.4.0
TL;DR: hardens the loopback surfaces (CSRF, DNS-rebinding, extension auth), makes the extension bridge survive high concurrency (backpressure, reconnect, per-tab serialization), and fixes snapshot-on-action and tab handling. Upgrading the daemon does not require reinstalling the extension.
Breaking changes
- Extension bridge caps concurrent operations at 6 by default. Beyond the cap, calls queue; past the operation deadline they return
extension bridge busy, retry with backoffinstead of running. Tune with--bridge-max-inflight(envBRW_BRIDGE_MAX_INFLIGHT), 0 disables. Concurrency was previously unbounded. - HTTP control plane rejects cross-origin browser requests (CSRF) and, on a loopback bind, a non-allowlisted
Host(DNS-rebinding). Loopback CLI, MCP, and curl send no browserOriginand are unaffected; a browser-based API consumer or a customHostgets 403. - Seamless bridge defaults:
focus_tabno longer raises the OS window, andbrw_openplaces tabs in a defaultbrwtab group. Restore with--bridge-raise-windowand--bridge-tab-group "".
Security
- Per-launch extension bridge auth token: minted each start, persisted 0600 at
~/.brw/bridge-token, served only over loopback. Non-breaking by default (a wrong token is rejected; an older extension that sends no token still connects, logged once). SetBRW_BRIDGE_REQUIRE_TOKEN=1to require it once every extension is reloaded. - navpolicy normalises hosts to ASCII/punycode, so a Unicode host and its
xn--form hit the same allow/deny rule (closes a blocklist-evasion gap). - Extension refuses every cookie CDP method and the whole
Storagedomain; cookies and passkeys cannot be read through brw even by a rogue local socket peer. - Non-browser (empty-Origin) websocket clients are rejected at the bridge.
Bridge resilience under load
- Backpressure on the shared socket with a typed busy signal so callers can back off (see breaking #1).
- Reconnect-aware: an RPC arriving during the MV3 service-worker reconnect gap waits for the socket instead of failing "not connected". Idempotent reads retry once on a transient drop; mutating ops never auto-retry.
- Per-tab serialization: operations on one tab no longer interleave their CDP frames; distinct tabs still run in parallel.
- WS frame write bound to its own deadline, so a cancelled or slow request can no longer tear down the shared socket.
/statusreports inflight, queued, busy_drops, retries.
Reliability
snapshot:trueon action tools now works across the MCP-server to bridge HTTP boundary (was dropped in the upstream-http topology).- WaitFor awaits a single in-page promise instead of polling a heavy condition, so concurrent waits no longer flood the debugger.
- Tab enumeration via
chrome.tabs.queryacross all window types (excludes only PWA/app and devtools). - Chrome stability: debugger detach on shutdown, graceful shutdown, profile guard, leak fixes.
- JS alert/dialog auto-dismiss.
Tools and usability
- New
brw_navigate_to: navigate an existing tab to a URL, wait for load, return an observation. snapshot:trueon all action tools includes a full PageSnapshot in the result.- Dynamic ref disambiguation for sibling elements sharing a name.
brw_fillerrors show the element tag and suggestbrw_type;brw_wait_foracceptspage_ready.
v0.3.0
Highlights
- Adds workspace/profile identity checks across bridge, HTTP health, upstream MCP wrapping, and extension bridge status so routed browser control fails closed on mismatches.
- Adds per-profile Chrome extension configuration UI/defaults for loopback bridge URL and expected workspace/profile.
- Adds device emulation support and keeps file-chooser upload support from the current mainline.
- Updates remote MCP/install docs with neutral examples and safer profile-routing guidance.
Verification
- go test ./...
- tracked-tree secret and machine-specific scans passed; local eval notes were left untracked and not included in the release.
brw v0.2.0
brw v0.2.0
A semantic-browser-control release focused on making the tool faster, more
accurate, and easier for small models to use — plus forward-looking WebMCP
and an opt-in navigation guardrail.
The Chrome extension/plugin is unchanged and stays at 0.1.0. Only the
daemon bumps to 0.2.0.
Small-model ergonomics
- Actionable error recovery —
ref not found/not actionablenow tell the
model to re-snapshot or inspect, instead of dead-ending. brw_observein thecoretool profile — the cheap "what changed" check is
now in the lean surface.brwd --print-system-prompt+docs/agent-guide.md— an opinionated,
token-efficient operating loop to prepend to an agent's system prompt.brw_snapshot format:"compact"— one terse line per element
(e17 button "Submit") instead of JSON; markedly fewer tokens, same refs.
Accuracy / coverage
- Closed shadow DOM piercing — closed-root web components (many design
systems) now show up as normal refs (document-start + in-walker install). - Cross-origin iframe signal — unreachable cross-origin frames are surfaced in
metadata.cross_origin_frames(box + origin) so the agent falls back to
brw_screenshot+brw_click_xyinstead of going blind.
Forward-looking / safety
- WebMCP (
--enable-webmcp) — brw acts as the agent-side
navigator.modelContextruntime;brw_page_toolslists and
brw_call_page_toolinvokes a cooperating site's declared tools. - Navigation guardrail (
--blocked-domains/--allowed-domains) — gates
brw_open/brw_open_incognito/brw_replay_requestso a prompt-injected
agent cannot steer the browser off-limits. Opt-in, off by default.
Full test suite green (incl. headless-Chrome integration tests for shadow,
cross-origin, and WebMCP).