Skip to content

Browser-fetch lane backed by Cloudflare Browser Run (Kitesurf) — replace the deferred real-Chrome lane #2

Description

@belikh

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

  • $HPR fetch --provider browser-run works standalone (extraction + screenshot asset)
  • Auto-fallback: simulated builtin failure → browser lane retry → note written with correct provenance frontmatter
  • Seeded 403/JUNK_CONTENT escalation drains end-to-end without human intervention
  • CAPTCHA/login-wall escalations still surface as needs_human (regression test)
  • Per-run lane budget enforced; token sourced from env only (never argv/config-file plaintext)
  • Docs: [web.browser_lane] config reference + beta-limit caveats

Non-goals

Solving challenges, storing site credentials, automating local browsers. Related but independent: #1 (Postgres backend).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions