A Browser capability for AI agents. Designed to be the bridge between Vercel Zero (compile-time effect declarations) and agent-trace (run-time semantic events). Same vocabulary, both ends of the timeline.
Status: v0.1. The Python runtime is real, tested (5/5 passing), and usable today. The Zero side (
zero/browser_cap.0) is a draft — Zero is four days old and the syntax here has not been verified by the compiler yet. Issues / PRs welcome from anyone with Zero installed.
In Zero, every function declares what side effects it can perform via capabilities in its signature:
fn login(browser: Browser, email: str, password: str) -> Session raises LoginError {
check browser.nav("https://example.com/login")
check browser.type("#email", email, false)
check browser.type("#password", password, true) // redact
browser.login_attempt("form")
check browser.submit("form#login")
// ...
}
Reading that signature, you know — before any code runs — that this function can perform nav, type, submit, login_attempt events. The compiler refuses code that performs anything else.
At runtime, every capability call emits the matching event into the agent-trace JSONL:
{"event_type":"nav", "data":{"from_url":"about:blank","to_url":"https://example.com/login","trigger":"user"}}
{"event_type":"type", "data":{"selector":"#email","value":"user@example.com","redacted":false}}
{"event_type":"type", "data":{"selector":"#password","redacted":true}}
{"event_type":"login_attempt", "data":{"provider":"form"}}
{"event_type":"submit", "data":{"form_selector":"form#login"}}The method name on the capability == the event_type in the trace. That's the load-bearing design choice. The compile-time signature and the run-time event share one vocabulary.
- Signatures become docstrings for observability. Read a function, know what its trace will contain. Today: zero connection between function signatures and runtime traces.
- Greppable audit. "Which functions can submit a form?" = grep signatures for
Browsercap withsubmitdeclared. "Which functions ran the antibot check?" = grep traces forantibot_detectedevents. - Subset capabilities.
ReadOnlyBrowserCapgrants onlynav/extract/screenshot/antibot_check. Calling.click()on it raises anAttributeError(Python) or fails to compile (Zero). Same effect, two enforcement points. - Differential debugging. If the signature says the function can emit
login_failedbut the trace doesn't contain one, you found a missing emission — bug in the capability implementation, not in the agent.
pip install zero-browserThis pulls in agent-trace as a dependency.
from agent_trace import Tracer
from zero_browser import BrowserCap, RecordingBackend, LoginReason, MfaType
from zero_browser.backends import ExtractResult
backend = RecordingBackend(
starting_url="about:blank",
extract_responses={
"document.body.innerText": ExtractResult(
query="document.body.innerText", result_count=1,
sample=["Invalid email or password."],
),
},
)
with Tracer(task="Log in", model="claude-opus-4-7") as tracer:
browser = BrowserCap(tracer, backend)
browser.nav("https://example.com/login")
browser.type("#email", "user@example.com", redact=False)
browser.type("#password", "wrong-password", redact=True)
browser.login_attempt("form")
browser.submit("form#login")
body = browser.extract("document.body.innerText")
if "Invalid email or password" in (body.sample[0] if body.sample else ""):
browser.login_failed(LoginReason.INVALID_CREDENTIALS, "text match")
tracer.end(status="failed", reason="login_failed_invalid_credentials")Render the trace:
agent-trace traces/<session-id>.jsonl
A full working example: examples/login_python.py.
The Zero equivalent (draft): examples/login.0.
See SPEC.md for the full mapping. Summary:
| Capability method | agent-trace event_type |
|---|---|
nav / click / type / submit |
same |
extract / screenshot / dom_snapshot |
same |
antibot_check |
antibot_detected (conditional — emits only on signal) |
login_attempt / login_success / login_failed |
same |
mfa_prompt / mfa_submitted |
same |
ReadOnlyBrowserCap grants only nav / extract / screenshot / antibot_check.
The capability layer doesn't care how the browser is actually driven. Plug in any backend that implements the Backend protocol:
RecordingBackend(shipped) — does nothing real, records calls. Useful for tests and dry runs.- Playwright backend — planned. Wraps
playwright.async_api.Pageso capability calls drive a real Chromium. - CDP backend — planned. For when you need the agent attached to an external browser (e.g., paired with agent-browser).
- MV3 extension backend — planned. Drives capability calls through messages to the agent-browser Chrome extension.
┌─────────────────────────────┐
│ Vercel Zero (the language) │
│ agent reads diagnostics, │
│ repairs its own code │
└──────────────┬──────────────┘
│ declares effects via Browser capability
▼
┌─────────────────────────────┐
│ zero-browser (THIS REPO) │
│ capability surface = │
│ trace vocabulary │
└──────────────┬──────────────┘
│ emits events at runtime
▼
┌─────────────────────────────┐
│ agent-trace (schema + lib) │
│ agent reads events, │
│ classifies failures │
└─────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ agent-viewer │ │ agent-debugger │
│ one-trace UI │ │ pdb breakpoints │
└──────────────────┘ └──────────────────┘
All four sibling repos (agent-trace, agent-viewer, agent-debugger, agent-browser) live under github.com/gotcs108 and compose freely.
- A working Zero compiler integration. Zero is days old, the syntax in
zero/browser_cap.0is a draft based on public design notes. Verifying it under the real compiler is a TODO; PRs welcome. - A real browser driver.
RecordingBackendis the only shipped backend. Playwright / CDP / MV3 backends are designed but not implemented — first-target one is a v0.2 issue. - Antibot solving.
antibot_checkdetects signals. It doesn't solve them. Different problem. - Async. The capability surface is sync to match Zero's no-implicit-async philosophy. An async variant for Python is on the roadmap but the order is: real backend first, async second.
- v0.2 — Playwright backend. The 80% use case. Real
nav/click/type/submitagainst actual Chromium. - v0.3 — Verify Zero side under the real compiler. File issues against Zero where the syntax we drafted doesn't match. Adjust SPEC accordingly.
- v0.4 — CDP backend. For agents that attach to a long-lived browser instance.
- v0.5 — Browser-backend (drives the agent-browser MV3 extension via WebSocket).
The single highest-priority contribution at v0.1 is schema gaps in the capability surface: a failure mode you've hit that the current capability vocabulary can't express. File it under Issues. Each gap shapes the surface toward agent-trace's v1 schema, which is when the names freeze.
Second priority: anyone with Zero installed running zero check zero/browser_cap.0 and reporting back. The syntax there is drafted, not verified.
MIT.