A browser for agents, shipped as a loadable TinyBus module.
tinybrowser drives a real Chrome over the Chrome DevTools Protocol — launching
it, navigating, snapshotting the accessibility tree, dispatching real input
events, extracting text, taking screenshots — and publishes all of it as a
handful of bus members. A host loads one cdylib and gets a browser without a
browser stack in its build.
OpenSession -> Navigate -> Snapshot -> Perform -> Snapshot -> ...
| |
ReadPage Screenshot
An agent host that wants to look at a web page has bad options. Shelling out to a browser CLI means a subprocess, a JSON parser around its output, and a binary to install and version-match. Linking a browser stack in means dragging a WebSocket client, a TLS stack, an image codec and a protocol surface into a binary that mostly does something else — and a crash anywhere in it is a crash in the host.
This is the third option: the browser lives behind a wire. The host keeps a
proxy and a serde derive.
A snapshot, not HTML:
- RootWebArea "Example Domain"
- heading "Example Domain" @e1
- paragraph "This domain is for use in illustrative examples." @e2
- link "More information..." @e3
That is the browser's own accessibility tree — an order of magnitude smaller
than the DOM, with hidden nodes already gone and every control carrying its
role, name, and state. The agent picks @e3 and passes it straight back as the
target of a click, so the thing it acts on is the thing it saw. A ref from an
older view is refused rather than resolved against whatever now occupies that
position.
| Member | What it does |
|---|---|
OpenSession / CloseSession / ListSessions |
Launch or attach a browser, and give it back |
Navigate |
Go somewhere, waiting as far as commit, load, or networkIdle |
Snapshot |
The accessibility tree, with refs |
Perform |
Click, fill, type, press, select, check, hover, scroll, wait, read, go back |
ReadPage |
The page as text, Markdown, or serialized DOM |
Evaluate |
JavaScript in, value out |
Screenshot + ReadOutput / ReleaseOutput |
An image, collected in chunks |
ContractVersion |
What a host checks before its first real call |
Every name and payload is published by tinybrowser-bus, a two-dependency crate
a host links instead of repeating string literals.
use tinybrowser::{Action, Browser, NavigateRequest, SnapshotRequest, Target};
# async fn example() -> tinybrowser::Result<()> {
let browser = Browser::new();
let session = browser.open_session(Default::default()).await?;
browser.navigate(&session.id, &NavigateRequest::new("https://example.com")).await?;
let snapshot = browser.snapshot(&session.id, &SnapshotRequest::interactive()).await?;
println!("{}", snapshot.tree);
browser
.perform(&session.id, &Action::Click { target: Target::parse("@e1"), new_tab: false })
.await?;
browser.close_session(&session.id).await?;
# Ok(())
# }crates/tinybrowser/examples/over_the_bus.rs is the reference: load the module,
wait for it to claim its name, check the contract version, then call. Run it
against a module you have built:
cargo build -p tinybrowser --release
cargo run -p tinybrowser --example over_the_bus -- \
target/release/libtinybrowser.so https://example.comdocs/openhuman-integration.md covers wiring it into an OpenHuman host and the
agent-facing tool that sits on top.
A Chrome or Chromium on the host, or a DevTools endpoint to attach to. The
module looks in the conventional places; TINYBROWSER_CHROME names one
explicitly, and TINYBROWSER_CHROME_ARGS adds launch flags every session needs
— --no-sandbox on a host where unprivileged user namespaces are restricted,
most often.
A host that already runs a browser should point the module at it instead, with
SessionOptions::endpoint.
git submodule update --init --recursive
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo build --all-targets --all-features
cargo test --all-featuresThe end-to-end suite drives a real browser and is opt-in, because a runner without one would fail it for the wrong reason:
TINYBROWSER_LIVE_TESTS=1 cargo test -p tinybrowser --test live_chromeAGENTS.md is the full working agreement. CLAUDE.md is a symlink to it.
The design owes a great deal to Vercel's
agent-browser: the
accessibility tree as the thing an agent reads, @ref addressing scoped to a
snapshot, and hit-testing a click point before dispatching at it. See
THIRD-PARTY.md.
GPL-3.0-only. See LICENSE.