Skip to content
patrickbdevaneyPublic

About

Independent web browser engine in Rust that renders the existing web and exposes each page to agents as an accessibility surface, with WebDriver BiDi automation. Stylo, Taffy, html5ever, SpiderMonkey. Pre-release.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

2,610 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Manuk

Manuk is an MCP server that lets a model operate websites through a structured accessibility view of each page (role, accessible name, state, hit-test box and a stable handle per element) rather than screenshots or selectors. It has two backends behind the same tools: Chrome for Testing (the one to use) and an independent browser engine written in Rust (deterministic and forkable, with no Chrome dependency, but behind on real sites; see the scoreboard).

Important

Pre-release. Nothing is tagged or published for this launch; build from source. The engine's status as a browser is under Status.

Use it

./scripts/mozjs-fetch.sh                      # once: pinned SpiderMonkey prebuilt (a clean-clone build needs it)
cargo auditable build --release -p manuk-mcp  # or: cargo build --release -p manuk-mcp
claude mcp add manuk -- manuk-mcp --backend chrome

--backend chrome drives the pinned Chrome for Testing (under ~/.local/chrome-cft/<pin>/, or MANUK_CHROME) with its sandbox on. Without the flag, manuk-mcp runs the in-process engine. Thin stdio clients: python/manuk_client.py (standard library) and ts/manuk.ts (Node built-ins). Tool-by-backend behaviour: docs/sprint/BACKENDS.md. Security policy and SBOM: SECURITY.md.

WebMCP. Tools a page registers through document.modelContext.registerTool, declarative toolname forms, and one synthesized fill-form tool per <form> appear as webmcp_<name> MCP tools with list_changed; a tool whose description holds paint-hidden text is withheld. Against Chrome's own registry on 6 demo pages the in-process engine matched tool names on 4 and names plus schemas on 1 (W3.20.b, gate not met; see docs/sprint/JOURNAL.md).

Scoreboard

The task suite and the bars were fixed in docs/sprint/SUCCESS.md before any result. Rows: docs/sprint/SCOREBOARD.tsv. The table is generated by python3 -I scripts/readme-check.py --emit, and the same script fails if it differs from the TSV (rule: the latest row per arm, task and run).

chrome_ver=145.0.7632.116, driving model Haiku 5.5, pass count per run (3 runs), from docs/sprint/SCOREBOARD.tsv:

arm own 40 tasks, runs 1/2/3 external 10 tasks, runs 1/2/3
Playwright MCP + Chrome 39 / 40 / 38 of 40 8 / 7 / 7 of 10
manuk-mcp --backend chrome 40 / 40 / 40 of 40 7 / 8 / 7 of 10
manuk-mcp (in-process engine) 39 / 39 / 38 of 40 7 / 5 / 7 of 10

Verdict (docs/sprint/VERDICT.md): Bar 1 met, Bar 2 not met, which SUCCESS.md reads as "a useful agent tool, but the engine is not the reason". Bar 2 failed on every branch of the decisive-win test: the hidden-instruction rate is 0 for the in-process engine and also ~0 for Playwright; on tokens the in-process engine uses more than the best Playwright arm (727 vs 517 in+out per task, W4.B4); the rollback branch measured 0 flips (0 of 44 failed tasks on the REAL deterministic subset). The Chrome backend therefore ships as the product, and the in-process engine as the deterministic, forkable research backend. On the REAL deterministic subset (47 tasks) the in-process engine passes 10-11 tasks, the Chrome backend 15-18 and Playwright 23-25 (W4.A6); the engine cannot yet drive those forms. On all 102 REAL tasks, with the LLM-judged evals scored by an owner-provided judge (openai/gpt-oss-120b, validated against positive, negative and agreement controls, W3.18.a.a.b), the tasks passed in at least 2 of 3 runs are: Playwright 52, the Chrome backend 35, the in-process engine 32 (runs 46/49/52, 35/36/40 and 35/31/30; docs/sprint/w318/real-judge-report.tsv).

Footprint

Measured against the pinned Chrome for Testing (chrome_ver=145.0.7632.116), 3 runs per row, local fixture pages so the numbers are not shared-cache artefacts. Method, raw rows and what is not claimed: docs/sprint/FOOTPRINT.md.

axis in-process engine Chrome reading
memory, 1 page (PSS) 31 MB 399-407 MB 0.08×
memory per page, 50 pages 12.4 MB (one process each), 4.9 MB (forks of one checkpoint) 20.1 MB (tabs in one browser) 0.62×, 0.24×
new page from a checkpoint 36-43 ms (fork, replay-based) 65-70 ms (new context and navigate) —
cold start to first observation 55-57 ms 305-314 ms 0.18×
real sites, per page (5 paired URLs) — — PSS 0.30-0.31×; wall clock slower (1.66-1.96× this run, not settled)

The memory gap narrows as pages accumulate, because Chrome tabs share most of their cost. On live sites the engine is smaller, but its single-page load time is behind Chrome's, mostly in subresource fetch (docs/sprint/PERF.md).

Purpose

Software agents that operate websites today either interpret screenshots or depend on DOM selectors that change with each deployment. WebMCP offers a semantic tool surface only on sites that adopt it, and WebDriver BiDi provides standard actuation but no accessibility surface. Because Manuk parses the DOM and solves layout itself, it derives, without executing page JavaScript, a semantic view of any page: each element's role, accessible name, interaction state, hit-test box and a stable address. An agent can perceive a page as structured data, act through standard WebDriver BiDi input that dispatches real DOM events, and verify the outcome, on sites that have made no provision for agents.

The same engine core serves three front ends: a desktop browser (shell), a headless agent browser (agent) and the WebAssembly demonstration (demo).

Status

Measured for the v1.2.0 release on a corpus of real sites rendered by both Manuk and Chromium from identical snapshots. 76 of 265 corpus sites were reachable by the reference Chromium (the remainder are blocked by bot protection for the reference itself) and all 76 are scored. "Full" counts a site that hangs the driver as zero; "measured-only" reports quality where a score was obtained. Method and per-site data: docs/RELEASE-v1.2.0.md.

axis measures measured-only full exit threshold
M1 render node placement relative to Chromium (shape ≥ 0.75), no overlap or overflow coverage 89.9%, shape 72.1% — ≥ 95% of in-scope sites
M2 drive perceive → address → act on page targets 78.9% (n = 60) 62.3% ≥ 95% render ∧ function
a11y accessibility tree role/name/state agreement with Chromium (F1) 82.0% (n = 65) 70.1% ≥ 90% of nodes

Web Platform Tests. About 496,000 WPT subtests pass in the project's internal harness (tests/wpt), tracked as a monotonic ratchet across releases. Results have not been submitted to wpt.fyi, and the figure is an internal measurement, not a published conformance claim. JavaScript conformance is provided by SpiderMonkey; Test262 results are not separately reported.

Release history: v1.0.0 (2026-08-21, notes), v1.1.0 (notes), v1.2.0 (notes). Live, generated project state: STATUS.md.

Architecture

component crate implementation upstream (license)
Networking engine/net reused hyper, rustls, tokio (MIT / Apache-2.0)
HTML parsing engine/html reused html5ever (MIT / Apache-2.0)
DOM engine/dom own —
Style engine/css reused, embedded unmodified Stylo, the cascade used by Servo and Firefox (MPL-2.0)
Layout engine/layout own (block, inline, float, table, positioning); flexbox and grid via Taffy Taffy (MIT)
Text engine/text reused parley, swash (MIT / Apache-2.0)
JavaScript engine/js reused, bound through a JsRuntime trait SpiderMonkey via mozjs (MPL-2.0)
Media engine/media own demux; decode via upstream symphonia, openh264
Accessibility engine/a11y own —
Paint engine/paint own display list; rasterization via tiny-skia tiny-skia (BSD-3-Clause)
Compositor engine/compositor own —
Pipeline engine/page own —
Automation bidi own WebDriver BiDi endpoint —
Agent agent own —

SpiderMonkey and Stylo are configured and bound, never patched internally. The JIT, garbage collector and sandbox are upstream code. All page content runs in a single process today; one OS process per tab is a decided design scheduled for the security phase. The breakdown of each crate, and the boundary with upstream code, is in docs/loop/HORIZON.md and docs/SPEC.md.

Automation protocol support

Manuk implements WebDriver BiDi, the W3C cross-browser automation protocol. It does not implement the Chrome DevTools Protocol, which is specific to Chromium and not a standard.

BiDi module implemented commands and events state
session new, end, status, subscribe, unsubscribe implemented
browsingContext create, close, getTree, navigate, traverseHistory, setViewport, captureScreenshot; events contextCreated, contextDestroyed, navigationStarted, domContentLoaded, load implemented
input performActions implemented
script evaluate, callFunction partial
network, storage, log, emulation, permissions — not implemented

Client libraries (Puppeteer, Selenium, Playwright's BiDi channel) have not yet been tested against this endpoint.

Getting started

Requirements: a Rust toolchain; SpiderMonkey's build prerequisites for the spidermonkey feature. Linux x86_64 is the verified platform; macOS and Windows build in CI but are not verified on hardware.

# Render a page to PNG, headless (no GPU or display required)
cargo run -p manuk-shell --no-default-features -- render https://example.com/ -o out.png --width 800

# Desktop browser window (winit + wgpu)
cargo run -p manuk-shell -- browse https://example.com/

# Headless agent browser (configure a model endpoint in .env, or use a local llama-server)
cp .env.example .env
cargo run -p manuk-agent --bin agent-run -- "What is this page's main heading?" https://example.com/

# JavaScript through SpiderMonkey and the live Stylo cascade. First fetch the pinned SpiderMonkey prebuilt:
# the script checks its sha256 against the pin and, when `gh` is authenticated, runs `gh attestation verify`.
./scripts/mozjs-fetch.sh
cargo test -p manuk-js --features spidermonkey
cargo test -p manuk-css --features stylo

# Tests and the internal WPT harness
cargo test --workspace
cargo run -p manuk-wpt

Capabilities

  • Rendering: block, inline, flex, grid, table, float and positioned layout; stacking contexts; overflow clipping; backgrounds, gradients, shadows, transforms; the full Stylo cascade including @layer, container queries and :has().
  • JavaScript platform: DOM, CSSOM and events; fetch and XHR; ES modules with import maps; custom elements and shadow DOM; mutation, intersection and resize observers; Web Animations; View Transitions; the Navigation API; IndexedDB; Cache API; Web and Service Workers (same thread); Content Security Policy; crypto.subtle.
  • Media: <video> playback of H.264 and AAC in MP4; Media Source Extensions partial.
  • Browser shell: forms and uploads, tabs with hibernation, history, bookmarks, find in page, zoom, RFC 6265 cookies with partitioned storage, session restore, an encrypted credential store with origin-scoped autofill, streaming downloads.
  • Agent surface: accessibility tree (role, accessible name, state, focus, geometry) computed without page JavaScript; occlusion-aware hit testing; actions that dispatch real DOM events; a provider-neutral inference interface; page text delivered to models only inside an untrusted-content boundary.
  • MCP tools: navigate, observe (full, viewport or diff; a tree-shaped snapshot with list, row, card and dialog context and frame-merged handles), extract(query) returning only matching passages, find, act with an effect diff and a dispatch-time hit-test check, type with real key events, scroll, composite fill_form(fields[]) and act(steps[]) that stop at the first dialog or navigation, upload, key, drag, dialog, gated downloads, screenshot, storage_state, and handoff (the agent pauses, a person acts, the agent resumes with a diff of what changed). Per-backend behaviour is in docs/sprint/BACKENDS.md.
  • Engine-only agent features: every act and navigate reports when the page has settled, read from the engine's own fetch and timer queues rather than a network-idle guess; checkpoint, restore and fork (replay-based, including a cookie and storage snapshot); action receipts listing the storage writes each act made; --zygote-after-load forks sessions from an already-loaded page (64-way fork verified on a page with a 3.9 MB DOM); --deterministic runs with a logical clock and seeded randomness. Retry-from-checkpoint and best-of-3 forking help on flaky forms, but the same layer over Chrome matches them (W4.C2, W4.C3).
  • Security defaults (agent mode): an ephemeral in-memory cookie and storage partition unless --profile is given; no file: loads from a web document; loopback, RFC 1918 and link-local addresses refused after DNS resolution, on fetch, WebSocket and proxy dials; a per-task origin allowlist enforced on every network channel; values read on one origin refused toward another (including encoded copies); secrets typed from the OS keyring through named handles and redacted from results; text a person cannot see is withheld from the model; SpiderMonkey's optimizing JIT tiers off (baseline tiers kept) and a Landlock filesystem ruleset on the headless binaries. The Chrome backend runs with Chrome's sandbox on; --unsafe-no-sandbox is the only way to turn it off. Each layer is pinned by a gate shown to fail without it (SECURITY.md).
  • Agent grants: manuk-mcp takes --read-origins and --write-origins (origin sets for navigation, reads, typing and POSTs), and --confirm=submit,download,navigate-new-origin (actions that need confirm=true). Credential and payment fields are never typed by the agent (HANDOFF), and out-of-set origins are REFUSED on both the in-process and Chrome backends (the Chrome blocked-iframe socket residual is listed in the gaps). Flags, verdicts and open gaps: docs/sprint/BACKENDS.md.

Known gaps and non-goals

Gaps on the Phase-0 path: placement fidelity (mean parent-relative shape about 0.69); roughly one in five in-scope sites not yet reaching a stable, scorable DOM; rich editing (contenteditable, Selection) and IME composition; WebAuthn; the M2 function certificate; adoption of a platform accessibility bridge. SpiderMonkey faults inside its own frames cannot be contained in-process until process-per-tab isolation lands. The WebAssembly demo has no JavaScript because SpiderMonkey does not target WebAssembly.

Out of scope by decision: Encrypted Media Extensions and DRM, WebRTC, WebGPU and heavy WebGL applications, HTTP/3. Manuk does not attempt fingerprint evasion or bot-detection circumvention.

How it is developed

Manuk is developed largely by an autonomous AI coding loop operating under human direction. Each change must pass a single all-or-nothing verification wall (scripts/verify.sh): build, WPT-derived and purpose-built correctness gates (about 570), box-geometry probes within ±3 px of headless Chromium, real-site fidelity, JavaScript conformance and performance floors. A capability counts only once a gate has been shown to fail without it, and any measured regression is reverted. Work is prioritized by a differential oracle that renders 265 real sites in Manuk and Chromium and clusters divergences by root cause. The method is documented in docs/loop/ and CONSTITUTION.MD. Responsibility for every change rests with the repository owner.

Contributing and security

External contributions are not being accepted during Phase 0. Vulnerability reporting and the supply-chain notes are in SECURITY.md; do not report vulnerabilities in public issues.

License

Mozilla Public License 2.0, as declared in the workspace manifest. Vendored and linked components remain under their own licenses, as listed in Architecture.

About

Independent web browser engine in Rust that renders the existing web and exposes each page to agents as an accessibility surface, with WebDriver BiDi automation. Stylo, Taffy, html5ever, SpiderMonkey. Pre-release.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages