bruster

bruster

A native webview browser driven by an agent over JSON lines on stdio. No Chromium download. No Node. One process of less than 1 MB.

bruster controls the engine that the operating system already ships: WKWebView on macOS, WebKitGTK on Linux, and WebView2 on Windows. The program is a small Rust binary built on wry. Agents drive it with one JSON object per line, or with the Model Context Protocol through --mcp.

CI Latest release MIT license macOS Linux Windows

Overview

bruster reads commands from stdin and writes its native protocol to stdout. It is one process with no bundled browser and no runtime. It uses both a line-oriented JSON protocol and the Model Context Protocol. The same binary works for a scripted scrape, a test harness, or an agent tool stack.

Installation

The install script downloads the build for this OS and CPU into ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/aliilyas/bruster/main/install.sh | sh

Prebuilt archives for every platform are on the releases page. To build from source, you need a Rust toolchain:

cargo build --release
Linux runtime. WebKitGTK 4.1 is necessary. Install it with one of these commands: apt install libwebkit2gtk-4.1-0, apk add webkit2gtk-4.1, or dnf install webkit2gtk4.1. If there is no desktop session, bruster starts again under xvfb-run -a when DISPLAY is not set.

Quickstart

Send one JSON object per line to stdin. Read the results and events from stdout:

$ bruster
→ {"id":1,"method":"navigate","params":{"url":"https://example.com"}}
← {"event":"load","tab":1,"url":"https://example.com/"}
← {"id":1,"result":{"url":"https://example.com/"}}
→ {"id":2,"method":"snapshot"}
← {"id":2,"result":{"url":"...","title":"Example Domain","elements":[{"ref":"e1","role":"heading","name":"Example Domain"}]}}
→ {"id":3,"method":"click","params":{"ref":"e1"}}
← {"id":3,"result":null}

Command-line usage

bruster [--mcp] [--hidden|--visible] [--quiet] [options]
--mcpuse the Model Context Protocol on stdio instead of the native protocol. This option also sets --hidden
--hidden / --visiblemove the windows off-screen / show the windows
--quietsend stderr to /dev/null. This mutes GL, ALSA, and GTK noise
--viewport WxHinitial window size, default 1280x800
--user-agent UAreplace the user agent
--profile DIRkeep cookies and storage between runs
--proxy URLhttp://host:port or socks5://host:port
--init-script FILEJavaScript that runs in every page before its own scripts
--insecureignore TLS errors (Linux only)
--no-imagesdo not load images. Pages load about 30% faster (Linux only)

Model Context Protocol

With --mcp, every method below becomes a tool. Page events are delivered as notifications/message. The windows stay hidden unless you add --visible.

opencode, Claude Desktop, Cursor, Windsurf, and Zed use the same shape:

{ "mcpServers": { "bruster": { "command": "bruster", "args": ["--mcp", "--quiet"] } } }
claude mcp add bruster -- bruster --mcp --quiet
codex mcp add bruster -- bruster --mcp --quiet

VS Code uses a servers key:

{ "servers": { "bruster": { "type": "stdio", "command": "bruster", "args": ["--mcp", "--quiet"] } } }

Native protocol

One JSON object per line, in both directions. A request carries id, method, and optional params. The reply carries the same id with a result or an error. You can address elements with {"selector": "css"} or with a ref from the last snapshot. With format: "text", a snapshot renders as one line per element. This is about 45% smaller than JSON:

https://example.com/
Example Domain
e1 heading "Example Domain"
e2 text "This domain is for use in..."
e3 link "Learn more" href=https://iana.org/help/example-domains
e4 checkbox "Remember me" checked=false

API reference

A selection of the available methods. The full table, with every parameter and result, is in the repository README.

MethodPurpose
navigateload a URL, optionally waiting for load, dom or idle
snapshotlist controls, headings, links and visible text, with refs
finda snapshot filtered by text or regex
click hoveract on a selector, ref or coordinates
fill type pressenter text and send keys
fill_formfill several fields in one call
select checkdrive selects and checkboxes
uploadset files on a file input
screenshotPNG to a path or as base64, optional full page and clip
evalrun JavaScript and return a JSON value
wait_forwait for a selector, text, URL or network idle
network consoleinspect requests, responses and console output
cookies set_cookieread and write cookies
new_tab tabs switch_tabmanage tabs that share one profile
closeexit the process

Events

Unsolicited messages use an event field: ready, navigating, load, tab_opened, tab_closed, dialog, tls_error, load_failed and download.

Limitations

Performance

Live comparison, runtime footprint and measurement history. Includes Bruster, Playwright, Puppeteer and agent-browser.

Development

bin/bruster runs the development build from a checkout. tests/run_all.sh [--rounds N] [--no-e2e] runs the full cycle. The cycle does a build, unit tests, smoke tests, edge tests, a leftover-process check, the MCP launch check, and the public-site end-to-end tests. On Linux, run the script under xvfb-run -a. CI builds and tests every platform. CI also publishes release archives on a v* tag.

License

bruster is released under the MIT License.