Problem
Blocked fetches (bot walls, auth walls, JS-only pages) currently dead-end into the escalation queue (escalation list --status queued) and wait for a human. The original design reserved a hyperresearch-browser-fetcher lane driving the user's real Chrome; in the opencode port that agent was never built, so the queue only accumulates. Meanwhile every run hits walls a plain HTTP fetcher can't pass: SPA docs that extract as junk, soft UA/bot walls, IP-throttled endpoints.
Proposal
Make Cloudflare Browser Run the supported browser-fetch provider, defaulting to the Kitesurf engine (agent-first, stateless, runs in CF isolates — nothing executes locally):
1. New fetch provider
[web.browser_lane]
enabled = true
engine = "kitesurf" # kitesurf | chromium (same API)
account_id = "{env:CF_ACCOUNT_ID}"
api_token_env = "CLOUDFLARE_BROWSER_RUN_TOKEN" # token read from env, never stored
Two integration depths:
- Quick Actions lane (v1): REST one-shots — HTML/content extraction, screenshot, PDF. Maps 1:1 onto
$HPR fetch and the existing --save-assets pipeline (screenshot lands as note asset exactly like today).
- CDP session lane (v2, optional):
chrome-remote-interface/puppeteer-core against the wss://…browser-run/devtools/browser?browser=kitesurf endpoint for multi-step JS-heavy pages.
2. Escalation-drain semantics
On fetch failure with wall signatures (anti-bot 403, JUNK_CONTENT on script-heavy pages, IP-throttled 429), auto-retry once through the browser lane before queueing. Notes record provenance in existing frontmatter: fetch_provider: browser-run-kitesurf. Login walls, CAPTCHAs and 2FA skip the lane entirely and stay needs_human — consistent with the standing policy that challenges are always the human's.
3. Cost/run discipline
Per-run cap on browser-lane fetches (same spirit as locus source_budget), plus per-account limits honored with backoff. Engine choice recorded per note so downstream steps know extraction came from a rendered page.
Why Browser Run/Kitesurf fits this project specifically
- No local browser: page-isolated execution happens in Cloudflare's sandbox — strictly safer than automating a real Chrome profile, and removes the entire "drive the user's actual browser" hazard that got the original lane deferred
- Crawls what crawlers can't: Kitesurf exists precisely for agents needing rendered pages; Chromium flavor remains available per-request for stubborn sites (drop the
browser=kitesurf param)
- Stateless by design: matches the fetcher's bursty fan-out economics; sessions are disposable
- Known non-goals respected: challenge handshakes and long authenticated sessions are explicitly unsupported upstream — which enforces our human-in-the-loop policy rather than fighting it
Acceptance criteria
Non-goals
Solving challenges, storing site credentials, automating local browsers. Related but independent: #1 (Postgres backend).
Problem
Blocked fetches (bot walls, auth walls, JS-only pages) currently dead-end into the escalation queue (
escalation list --status queued) and wait for a human. The original design reserved ahyperresearch-browser-fetcherlane driving the user's real Chrome; in the opencode port that agent was never built, so the queue only accumulates. Meanwhile every run hits walls a plain HTTP fetcher can't pass: SPA docs that extract as junk, soft UA/bot walls, IP-throttled endpoints.Proposal
Make Cloudflare Browser Run the supported browser-fetch provider, defaulting to the Kitesurf engine (agent-first, stateless, runs in CF isolates — nothing executes locally):
1. New fetch provider
Two integration depths:
$HPR fetchand the existing--save-assetspipeline (screenshot lands as note asset exactly like today).chrome-remote-interface/puppeteer-core against thewss://…browser-run/devtools/browser?browser=kitesurfendpoint for multi-step JS-heavy pages.2. Escalation-drain semantics
On fetch failure with wall signatures (anti-bot 403,
JUNK_CONTENTon script-heavy pages, IP-throttled 429), auto-retry once through the browser lane before queueing. Notes record provenance in existing frontmatter:fetch_provider: browser-run-kitesurf. Login walls, CAPTCHAs and 2FA skip the lane entirely and stayneeds_human— consistent with the standing policy that challenges are always the human's.3. Cost/run discipline
Per-run cap on browser-lane fetches (same spirit as locus
source_budget), plus per-account limits honored with backoff. Engine choice recorded per note so downstream steps know extraction came from a rendered page.Why Browser Run/Kitesurf fits this project specifically
browser=kitesurfparam)Acceptance criteria
$HPR fetch --provider browser-runworks standalone (extraction + screenshot asset)needs_human(regression test)[web.browser_lane]config reference + beta-limit caveatsNon-goals
Solving challenges, storing site credentials, automating local browsers. Related but independent: #1 (Postgres backend).