Skip to content

Architecture

Sam LABBE edited this page Oct 13, 2026 · 1 revision

Architecture

Module map

src/main.rs          HTTP server (std::net), routes, agent-first JS snippets,
                     CLI subcommands (serve/state/creds/install-daemon), keystore routes
src/mcp.rs           MCP stdio adapter + serve auto-start
src/keystore.rs      OS-keychain store — logged-in states (jars) and origin-bound credentials;
                     only metadata ever returns over the API
src/webviewkit.rs    the kit contract — a trait every backend must implement,
                     so surface parity is compile-enforced (a backend that misses a
                     primitive or drifts on a signature won't build)
src/backend_macos.rs WKWebView via raw objc2 — ghost windows, lazy attach,
                     measured cold-start ordering (AppKit -> listener -> pre-warm),
                     WKUIDelegate panel runner (passkey ceremony, JS dialogs)
src/backend_wry.rs   Windows (WebView2) / Linux (WebKitGTK) via wry + tao —
                     same surface, IPC-shim results, URL-matched navigation
src/backend_stub.rs  fallback for other targets (placeholder, same contract)

The 8 primitives (navigate, read, screenshot, click, type, evaluate, wait, sessions) are engine-agnostic; each platform backend is a thin layer over the system WebView behind this exact surface — pinned by the WebviewKit trait, the seam a future hand-rolled backend (direct WebKitGTK/WebView2 FFI, no wry) would plug into.

The kit contract

Every backend implements the same trait (webviewkit.rs). This is what keeps macOS, Windows and Linux honest: a backend that misses a primitive or drifts on a signature fails to compile. v1.8.0 introduced it; the passkey work (v1.9.x) extended it with the auth-ceremony capability so the WKUIDelegate panel runner is part of the contract, not a macOS side-door.

Engine strategy — system-first, embedded fallback

Tier When Engine
1 — system engine the 95% case WKWebView (macOS), WebView2 (Windows — Chromium, preinstalled on every Win10/11), WebKitGTK via system package (Linux)
2 — official embed no system engine WebView2 Fixed Version (pinned runtime bundled with the app, Microsoft-sanctioned); macOS never needs it
3 — bare Linux containers headless boxes WebKitGTK via apt (distro-patched, never a vendored fossil) or WPE WebKit (~60 MB, no desktop stack, built for embedded); still 2–7× lighter than Chromium with full rendering

The rule behind the tiers: we do not vendor a browser the way Playwright does. That trade is the thing navette exists to refuse. On Windows the headline gets better for free: WebView2 is Chromium — navette delivers Chromium-grade rendering from a <1 MB binary with zero download.

Analogy: headless Chromium is the Postgres of scraping; navette is the embedded SQLite. SQLite won because nobody wants to run a server to hold a little state; navette wins because nobody wants to download a browser to read one page.

Daemon lifecycle

  • navette serve — one process, all sessions inside it.
  • navette install-daemon — resident mode:
    • macOS: LaunchAgent with KeepAlive
    • Linux: systemd user unit (Restart=always, WantedBy=default.target)
    • Windows: schtasks scheduled task
    • All run navette serve --port 8765. Cold start an agent feels: 24–37 ms; first page 24 ms; with --idle-release MIN, idle sessions drop and re-warm in ~100 ms while the daemon never exits.
  • Cold-start ordering on macOS is measured, not guessed: AppKit up → listener bound → pre-warm. The health endpoint answers as soon as the listener is up; the first session warms in the background.

MCP adapter

src/mcp.rs speaks stdio MCP and translates 19 tool calls to loopback HTTP. It auto-starts serve if nothing is listening, and idles politely when the port is already served by another navette — hosts that spawn the MCP server as a subprocess and hosts that attach to a resident daemon behave identically.

Why no CDP

CDP is a protocol built for DevTools, not for agents. navette speaks plain JSON HTTP and MCP — the protocols agents already speak. Not a Playwright drop-in, and that is deliberate; a thin CDP shim can come later if the world asks (see FAQ and Philosophy).

Clone this wiki locally