English | 中文
A single-binary, headless browser orchestration service for AI agents, written in Rust. rutter manages a real browser engine as a supervised child process, exposes a structured view of pages (accessibility-tree snapshots) instead of pixels, executes typed actions with deterministic semantics, and offers a local supervision dashboard with human approval for sensitive operations.
| Document | Role |
|---|---|
docs/architecture.md |
Reading-order entry point: crates, runtime shape, invariants |
docs/glossary.md |
The normative domain vocabulary |
docs/tool-catalog.md |
The MCP tool surface: transport, semantics, auto-wait, error mapping |
docs/snapshot-format.md |
The snapshot contract: serialization, references, token budget |
docs/read-format.md |
The read contract: markdown extraction, guards |
docs/engine-supervision.md |
Engine trait, binary acquisition, supervisor, CDP notes |
docs/sessions.md |
Session model, action path, storage state, recovery |
docs/events.md |
Event vocabulary, backbone semantics, replay |
docs/policy.md |
Action classes, verdicts, fail-closed rules, approvals |
docs/dashboard.md |
Dashboard server, access control, WebSocket protocol |
docs/testing.md |
Test levels, contract pins, how to run |
CONTRIBUTING.md |
Working rules and local gates |
Every source directory carries a README.md stating its
responsibility, boundary, and file map (the five shared test-helper
directories — tests/common/, crates/engine-cdp/tests/common/,
crates/session/tests/common/, crates/dashboard/tests/common/, and
crates/mcp/tests/common/ — are covered by their parent test READMEs)
— start at
crates/README.md. Each README and each
docs/ document has a Chinese mirror: README.zh.md beside its
README.md, and <name>.zh.md beside <name>.md under docs/;
the two languages are updated together.
# One-shot diagnostic: navigate and print a YAML snapshot to stdout.
rutter open https://example.com
# One-shot scrape: navigate and print the page as markdown.
rutter read https://example.com
# MCP server over stdio: connect any MCP client (engine headless;
# --headed runs a visible window instead).
rutter serve
# The same MCP server over streamable HTTP, with the supervision
# dashboard and a policy file attached.
rutter serve --http 127.0.0.1:8080 --dashboard 7700 --policy policy.toml
# Browse mode (no subcommand): a headed engine window you drive by hand.
rutterGlobal flags (valid on every mode):
| Flag | Environment | Meaning |
|---|---|---|
--engine-executable <PATH> |
— | Use this browser binary; skips download and cache |
--cache-dir <DIR> |
RUTTER_CACHE_DIR |
Engine cache root (default: OS cache dir + rutter) |
--engine-arg <ARG> |
— | Extra argument passed to the engine process (repeatable) |
Serve flags (accepted on every mode, effective on rutter serve only):
| Flag | Meaning |
|---|---|
--http <ADDR> |
Serve MCP over streamable HTTP on that address instead of stdio |
--dashboard <PORT> |
Attach the supervision dashboard on 127.0.0.1:<PORT> |
--policy <FILE> |
Load the supervision rule set from a TOML file |
--allow-remote |
Confirm a non-loopback --http bind (the transport has no authentication) |
On first use rutter resolves a browser binary in this order: an
explicit --engine-executable, the engine cache, then the Chrome for
Testing stable channel (headless shell for open, full Chrome for
browse mode when no system browser is found). The download happens
once; the cached version is reused until the cache directory is
cleared, including offline. Browse mode prefers a system-installed
Chrome or Edge when present.
The engine is supervised: heartbeats detect a dead process, restarts use capped exponential backoff, and a sliding-window circuit breaker stops restart storms — a crashed engine surfaces as an error on affected operations, never as a crash of rutter.
Actions are classified (navigation, pointer, keyboard, selection,
scroll, cookies) and judged against a rule set of class × URL pattern → verdict loaded from a TOML file. Verdicts are allow, deny, and
require_approval; navigations are judged on their canonicalized
target URL, and an unreadable page fails closed to a human decision.
Cookies require approval by default.
From source (requires Rust 1.88+):
cargo install --path crates/cliRelease archives for Windows (msvc), macOS (x64/arm64), and Linux
(x64) are cut by cargo-dist (cargo dist build, configured in the
[workspace.metadata.dist] section of the root Cargo.toml). The
browser engine itself is not bundled — rutter downloads Chrome for
Testing into its cache on first use (or point --engine-executable
at an existing binary).
rutter/
├── docs/ # code-facing documentation (English + zh mirrors)
├── scripts/ # quality-gate helpers run by CI
├── crates/ # workspace members (see below)
├── tests/ # cross-crate acceptance tests driving the binary
├── frontend/ # dashboard sources (vanilla JS, no build step)
└── browser/ # optional Electron engine shell rutter can attach to
browser/ is not a crate and ships no Rust: it is the Electron shell
that --engine-executable can point at, giving rutter a real window
with a supervision toolbar
(docs/engine-supervision.md). The Rust
workspace itself stays a single binary.
| Crate | Responsibility |
|---|---|
rutter-core |
Shared domain vocabulary: actions, snapshots, references, errors |
rutter-engine |
Engine and page traits, binary downloader, supervisor |
rutter-engine-cdp |
The only crate that speaks CDP (chromiumoxide) |
rutter-observe |
In-page scripts plus the snapshot builder |
rutter-events |
Typed event backbone: bus, ring buffers, replay |
rutter-session |
Orchestration: contexts, pages, actions, auto-wait |
rutter-mcp |
MCP tool surface (rmcp) |
rutter-policy |
Rule set, verdicts, approval broker |
rutter-dashboard |
Local supervision dashboard (events, approvals) |
rutter (cli) |
Binary entry modes: browse, serve, open, read |
Requires a stable Rust toolchain (1.88 or newer).
cargo build
cargo test --all
cargo clippy --all-targets -- -D warnings
cargo doc --no-deps
cargo fmt --all -- --checkQuality gates, identical to CI:
bash scripts/check_headers.sh # every source file opens with a header
bash scripts/check_encoding.sh # tracked text files: UTF-8, LF, no BOMCI also gates workspace line coverage: scripts/check_coverage.sh
checks the cargo-llvm-cov report against a threshold (90 % in CI,
engine suites and e2e suites included). The gate measures the Rust
workspace; the JavaScript sources (frontend/, browser/) are
covered by a syntax gate, not a coverage number.
Engine integration tests need a real binary and are #[ignore]d by
default; run them explicitly (they reuse the cache rutter open
fills):
cargo test -p rutter-engine-cdp --tests -- --ignored
cargo test -p rutter-integration-tests --test mcp_e2e -- --ignored
cargo test -p rutter-integration-tests --test approval_e2e -- --ignored
cargo test -p rutter-integration-tests --test http_e2e -- --ignored
cargo test -p rutter-integration-tests --test open_e2e -- --ignored
cargo test -p rutter-integration-tests --test read_e2e -- --ignoredscripts/smoke_open.sh drives 10 real sites through rutter open and
prints a pass/fail summary; scripts/benchmark.sh runs the 20-site
navigate+snapshot benchmark with a 90 % success bar.
- Commits follow Conventional Commits, English, imperative mood.
- Code comments may be written in Chinese or English; documentation
ships as English
README.mdwith ChineseREADME.zh.mdmirrors, updated together. - Security issues are reported privately — see
SECURITY.md. - License: Apache-2.0 (see
LICENSE).