CLI-first browser control for agents:
- deterministic JSON output
- explicit handles (
sessionId,targetId) - typed failures (
code,message, optional hints)
If you want the full machine contract, run:
surfwright contractRecommended for agent workflows:
npx skills add marcohefti/surfwrightCLI install options:
npm i -g @marcohefti/surfwrightbrew tap marcohefti/homebrew-tap && brew install surfwrightsurfwright open https://example.com
surfwright target snapshot <targetId> --mode orient
surfwright target find <targetId> --text "Pricing" --first
surfwright target click <targetId> --text "Pricing" --proof
surfwright target read <targetId> --selector main --chunk-size 1200 --chunk 1workspace.*: project-local profile setupsession.*: create/reuse/attach/clear sessionsextension.*: register/reload/remove unpacked extensionsopen: navigate and return handlestarget.*: inspect, extract, click, fill, wait, download, network capturerun: execute JSON plansdoctor: runtime capability diagnosticscontract: compact/full schema lookup
- JSON-first by default
--output-shape <full|compact|proof>for smaller envelopes- typed errors for deterministic recovery routing
- use
--no-jsononly for human-readable output
Examples:
surfwright --output-shape compact open https://example.com
surfwright --output-shape proof target click <targetId> --text "Checkout" --proofUse workspace profiles for persistent login state:
surfwright workspace init
surfwright open https://github.com/login --profile auth --browser-mode headed
surfwright open https://github.com --profile authRegister unpacked extensions once; managed sessions apply the latest build automatically:
surfwright extension load ./dist/my-unpacked-extension
surfwright open https://example.com --profile auth
surfwright extension reload my-unpacked-extension
surfwright open https://example.com --profile authRuntime verification defaults to strict:
SURFWRIGHT_EXTENSION_RUNTIME_MODE=strict(default): fail withE_EXTENSION_RUNTIME_NOT_LOADEDwhen not observedSURFWRIGHT_EXTENSION_RUNTIME_MODE=warn: continue withappliedExtensions[*].stateevidenceSURFWRIGHT_EXTENSION_RUNTIME_OBSERVED_WAIT_MS=<ms>: observation window
For extension automation, prefer Chromium/CfT when stock Chrome blocks unpacked side-load flags:
surfwright --browser-executable /path/to/chrome-for-testing doctor
SURFWRIGHT_BROWSER_EXECUTABLE=/path/to/chrome-for-testing surfwright open https://example.com --profile authsurfwright doctor
surfwright contract --profile browser-core
surfwright contract --command "target click"
surfwright contract --commands open,target click,target readDaemon control:
SURFWRIGHT_DAEMON=0: force direct mode (no daemon)SURFWRIGHT_DAEMON=1: force daemon mode- unset: daemon-on default
ARCHITECTURE.mddocs/architecture.mddocs/release-governance.mddocs/agent-guidance-architecture.mdskills/surfwright/SKILL.md
Pre-alpha. The surface is evolving quickly, but core handle-based flows are stable for daily agent loops.
Declared: February 13, 2026
We celebrate this as the milestone where we found the testing path that became Zero Context Lab, and fresh agents, with near-zero guidance, successfully discovered and used SurfWright workflows on first try.
Zero Context Lab: https://github.com/marcohefti/zero-context-lab
┌─────────────────────────────────────────────┐
│ │
│ Z E R O C O N T E X T D A Y │
│ │
│ the surface spoke for itself. │
│ │
└─────────────────────────────────────────────┘