{"slug": "show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost", "title": "Show HN: Jev-browse – browser sub-tasks for coding agents at ~1/3 the cost", "summary": "Developer danielnc released jev-browse, an MIT-licensed port of browser-use/jev-ultrafast that adds fast_run helpers to browser-harness so coding agents like Claude Code and Codex can hand off an entire browser sub-task in one call. Each step is decided by TypeSafe Jev, a small model answering typed questions in a few hundred milliseconds, and in the author's runs form and navigation tasks were 1.6–3.0× faster and 2.1–5.3× cheaper than the agent driving browser-harness alone at the same pass rate. The tool requires Chrome, browser-harness, Python 3.11+, and a TypeSafe API key, and hands control back to the agent on unknown values, risky clicks, frames, uploads, or sensitive fields.", "body_md": "**Fast, typed browser sub-tasks for coding agents.** jev-browse adds a few helpers to\n[browser-harness](https://github.com/browser-use/browser-harness) so that Claude Code or Codex can hand off a\nwhole website sub-task in one call: \"search Lisbon, set these two filters, open Casa Flora\". Each step is decided by\n[TypeSafe](https://docs.typesafe.ai) Jev, a small model that answers typed questions in a few hundred milliseconds. The\nagent then gets the outcome, or a typed reason why it stopped.\n\n```\n# inside a browser-harness script\nr = fast_run(\"https://en.wikipedia.org/wiki/Main_Page\",\n             \"Open the Wikipedia article on Gödel's incompleteness theorems\", run_id=\"demo-1\")\nprint(r.status, r.reason, r.url)      # claimed_done None https://en.wikipedia.org/wiki/G%C3%B6del%27s_...\njev_close(r.target_id)\n```\n\n**Why.** When a coding agent drives a browser itself, each click costs a model turn that re-reads its whole\ncontext. A five-field form becomes fifteen turns. `fast_run` does the clicking and typing in one call, with one Jev\nrequest per decision, and hands back to the agent only when it must: a value it doesn't know, a risky click, a\nframe or upload it can't handle, or anything sensitive. In the author's runs that made form and navigation tasks\n**1.6–3.0× faster and 2.1–5.3× cheaper** than the agent driving browser-harness alone, with the same pass rate\n([details](#benchmark)).\n\nIt is a port of [browser-use/jev-ultrafast](https://github.com/browser-use/jev-ultrafast) (MIT), turned into\nhelpers any agent can call from a browser-harness script.\n\nYou need Chrome, [browser-harness](https://github.com/browser-use/browser-harness) connected to it, Python 3.11+,\nand a **TypeSafe API key** from [console.typesafe.ai/keys](https://console.typesafe.ai/keys).\n\nPaste this into Claude Code or Codex:\n\n```\nInstall jev-browse from https://github.com/danielnc/jev-browse by following its install.md: clone it, run its\ninstaller, store my TypeSafe API key in the browser-harness agent-workspace .env (ask me for it; never print it),\nand run `python3 -m jev_browse doctor` until it passes. Ask me which text backend I want (default: my Claude\nsubscription if the claude CLI is installed) and whether to add the jev-browse pointer to my global agent\ninstructions.\ngit clone https://github.com/danielnc/jev-browse ~/jev-browse && cd ~/jev-browse\npython3 -m jev_browse install          # adds the helpers to browser-harness and links the skill\nENV=~/.config/browser-harness/agent-workspace/.env\nprintf 'TYPESAFE_API_KEY=%s\\n' '<your key>' >> \"$ENV\" && chmod 600 \"$ENV\"\npython3 -m jev_browse doctor           # checks everything and prints what is active\nbrowser-harness <<'PY'\nr = fast_run(\"https://en.wikipedia.org/wiki/Main_Page\", \"Open the Wikipedia article about the Eiffel Tower\",\n             run_id=\"hello-1\")\nprint(r.status, r.url)\njev_close(r.target_id)\nPY\n```\n\nThen add the [global pointer](#tell-your-agent-about-it) to your agent's instructions. Without it, agents\nrarely think to use jev-browse on their own.\n\n```\n your agent (Claude Code / Codex)\n   │  writes one browser-harness script:  r = fast_run(url, goal, values={...})\n   ▼\n browser-harness  ──CDP──►  Chrome: a new background tab owned by jev-browse\n   │                           │\n   │   ┌───────────────────────┘\n   │   ▼\n   │  loop:  snapshot the page (snapshot.js: visible text, controls, fields; sensitive values never read)\n   │         → one TypeSafe Jev request: next operation? which target? which value?  ──►  api.typesafe.ai\n   │         → value missing from the goal?  ask the text backend once (optional)   ──►  Claude / Codex /\n   │         → safety gates: commit verbs, sensitive fields, frames, uploads, hosts        Ollama / any\n   │         → click / type / select / scroll via CDP                                     OpenAI-compatible\n   │  until DONE, BLOCKED, or a typed hand-back (confirm_required, in_frame, text_value_unavailable, …)\n   ▼\n RunResult(status, reason, url, evidence, trace)  +  a JEV_BROWSE_RESULT={...} line to verify in the same script\n```\n\n- **One decision = one small Jev request** (typically a few hundred milliseconds). No screenshots and no large\nmodel in the loop.\n- **Values** come from your`values=` , from the goal itself (Jev picks among candidates taken from the goal), or,\nonly after a miss, from a text backend. A grounding gate checks the backend's answer before anything is typed.\n- **It never guesses past its limits.** Too many options, frames, shadow DOM, canvas, uploads, missing values,\nsensitive fields, or a click that would send, pay, delete, or book all hand back with a`Reason` . The tab stays\nopen for the agent to finish or resume.\n\nMore: [docs/architecture.md](https://github.com/danielnc/jev-browse/blob/main/docs/architecture.md).\n\n| Use `fast_run` for | Use browser-harness directly for | \n|---|---|\n| Multi-step forms and searches (fill, pick dates, filter, open a result) | Anything visual: charts, layouts, images, \"does this look right\" | \n| Link navigation to a known destination | Iframes, shadow DOM, canvas, file uploads, drag and drop | \n| \"Find and click the X\" steps ( `jev_find` /`jev_click` ) | Sensitive pages (banking, health, credentials) | \n| Sub-tasks where you only need the outcome | Pages whose text you should not send to TypeSafe | \n\nWhen `fast_run` hands back, the agent continues with the harness on the same tab, or resumes after supplying\nwhat was missing: `fast_run(None, goal, target_id=r.target_id, values={...})`.\n\nZero config beyond `TYPESAFE_API_KEY`. Everything else is an environment variable (the harness `.env` counts) or\nan entry in `~/.config/jev-browse/config.toml`. The environment wins. The settings you are most likely to change:\n\n| Setting ( `config.toml` ) | Environment | Default | \n|---|---|---|\n| `text.backend` | `JEV_BROWSE_TEXT_BACKEND` | `auto` :`claude` if its CLI is installed, else`none` | \n| `text.fallback` | `JEV_BROWSE_TEXT_FALLBACK` | `auto` : who answers when a local backend fails | \n| `ollama.url` ,`ollama.model` | `JEV_BROWSE_OLLAMA_URL` ,`_MODEL` | unset, `qwen3:30b-a3b` | \n| `openai.base_url` ,`openai.model` ,`openai.api_key_env` | `JEV_BROWSE_OPENAI_*` | unset | \n| `jev.model` | `JEV_BROWSE_JEV_MODEL` | `jev-latest` | \n| `run.max_actions` ,`run.timeout_s` | `JEV_BROWSE_MAX_ACTIONS` ,`JEV_BROWSE_TIMEOUT_S` | 30, 90 s | \n| `safety.allowed_hosts` | `JEV_BROWSE_ALLOWED_HOSTS` | all hosts | \n\n**Privacy note on `text.fallback`.** With a local (` ollama`) or OpenAI-compatible backend, the default\n`text.fallback = \"auto\"` means: if that backend fails its known-answer check, is unreachable, or returns invalid\noutput twice, **the `claude` CLI answers instead (when it is installed), so the goal, field labels, and page\nexcerpt go to Anthropic.** If you chose a local model to keep page text on your machine, set\n`text.fallback = \"none\"` (`JEV_BROWSE_TEXT_FALLBACK=none`): the miss then hands back to your agent. `doctor`\nprints which fallback is active.\n\nAll settings, and common setups (privacy mode, local model, OpenRouter/Groq/Cerebras/Gemini):\n[docs/configuration.md](https://github.com/danielnc/jev-browse/blob/main/docs/configuration.md). `python3 -m jev_browse config` shows what is active and where each\nvalue came from.\n\nA text backend is asked only when a field's value is implied but not stated (\"the capital of France\" → `Paris`).\n\n| Backend | Text goes to | Cost | Trade-off | \n|---|---|---|---|\n| `claude` (default if installed) | Anthropic, via your Claude subscription | subscription only; API keys are stripped | a few seconds per miss (CLI start-up, mostly hidden by a pre-started process) | \n| `codex` | OpenAI, via your ChatGPT subscription | subscription only | a few seconds of CLI start-up per miss; **not yet benchmarked** | \n| `ollama` | your own server (and the fallback's provider if it fails; see `text.fallback` ) | free per token | as fast as your hardware; guarded by a known-answer canary | \n| `openai` | any OpenAI-compatible endpoint (and the fallback's provider if it fails) | provider prices | unmeasured; bring your own model | \n| `none` | nowhere | free | misses hand back to the agent (privacy mode) | \n\nPersonal fields (name, email, phone, address) and sensitive fields are **never** sent to a text backend. Honest\nnumbers and set-up notes: [docs/backends.md](https://github.com/danielnc/jev-browse/blob/main/docs/backends.md).\n\n- **What leaves your machine.** On every decision, visible page text, element labels, non-personal field values,\nURL, and title go to**TypeSafe** (`api.typesafe.ai` ). After a miss, the goal, field labels, and up to 2,000\ncharacters of page text go to your**text backend** , or to its fallback when a local backend fails (see`text.fallback` above). Use it only on pages you are comfortable sending there. Use`text_backend=\"none\"` (or`text.backend = \"none\"` ) for sensitive sites.\n- **Sensitive fields** (passwords, one-time codes, card numbers, CVV, IBAN, national IDs) are never typed, never\nread out of the page, and never sent. Personal fields are reported only as filled or empty.\n- **Commit gate.** Clicks that send, pay, delete, book, or confirm need the goal's explicit authorisation, or your`confirm=[...]` in a*later* script. Otherwise the run hands back`confirm_required` . This is a heuristic (verbs\nplus structural signals such as a confirmation inside a dialog): it lowers the risk of an unwanted click in your\nsigned-in browser. It does not remove it.\n- **Owned tabs.** jev-browse works only in background tabs it created (or that your`new_tab()` created and you\nadopted). It never touches, focuses, or closes your other tabs.\n- **Hosts.**`safety.allowed_hosts` restricts every page jev-browse opens, adopts, or observes.\n- **No telemetry in jev-browse.** browser-harness has its own telemetry, which sends script text and helper-call\narguments to PostHog when enabled. The installer and`doctor` warn if it is on. Opt out with`browser-harness telemetry disable` .\n- **Local data.** Run files, traces, and screenshots can contain page text and typed values. They stay in the\nharness tmp dir and other gitignored paths, and`make clean-traces` removes them.\n\nA skill that never triggers delivers nothing. With only the skill installed, the calling agent used jev-browse in\n**0 of 5** unprompted tasks in the author's runs. After a short pointer in the global instructions it used it in\n**2 of 5**, and the explicit `fast_run` call shape saved a turn per task. Paste this into `~/.claude/CLAUDE.md`,\n`~/.codex/AGENTS.md`, or your project's agent file:\n\n```\n## Browser tasks: jev-browse fast path\nFor a multi-step website sub-task (search, fill, filter, open a result) where you only need the outcome, call\njev-browse from a browser-harness script. You don't need to load its skill first:\n\n    r = fast_run(url, goal, values={...known field values...}, run_id=\"<unique>\")\n    print(r.status, r.reason, r.detail, r.target_id)\n\n- `claimed_done` is not proof: check the printed JEV_BROWSE_RESULT line, or `js(\"...\", target_id=r.target_id)`,\n  in the same script, then `jev_close(r.target_id)`.\n- On a hand-back (`r.reason`), load the jev-browse skill for what to do next. Resume on the same tab with\n  `fast_run(None, <same goal>, target_id=r.target_id, values={...})`; never re-run from the URL.\n- Never act on `confirm_required` in the same script: decide first (ask me if my request does not clearly cover\n  it), then resume with `confirm=[...]`.\n- Use browser-harness directly for visual judgement, frames, uploads, and sensitive pages. Page text goes to\n  TypeSafe; pass `text_backend=\"none\"` on sensitive sites.\n- Close only tab ids that jev-browse returned to you.\n```\n\nThe same snippet is in [docs/global-pointer.md](https://github.com/danielnc/jev-browse/blob/main/docs/global-pointer.md).\n\n- No iframes, shadow DOM, canvas or visual understanding, file uploads, or pop-up tabs: these hand back.\n- Pages with very many options or very large state hand back (`too_many_options` ,`state_too_large` ).\n- Decisions are text-only. A page whose meaning is visual will confuse it, and it will usually say so\n(`visual_only` ,`low_confidence` ).\n- Every decision is a metered TypeSafe request: a few tenths of a cent per task at the time of writing.\n- The commit gate and the grounding gate are heuristics. Review what a run did (`r.trace` ) on anything that\nmatters.\n- The Codex and OpenAI-compatible backends are unmeasured.\n- Tested with browser-harness 0.1.13 on macOS with Chrome. Other platforms should work but have not been benchmarked.\n\njev-browse was compared with the same coding agent driving browser-harness directly, on public-site navigation,\nform, and filter tasks, with every outcome verified by code. In the author's runs it was **1.6–3.0× faster and\n2.1–5.3× cheaper**, with the same pass rate (N = 3 each), mostly because the agent needs far fewer turns. Your\nnumbers will differ. Summary: [docs/benchmark.md](https://github.com/danielnc/jev-browse/blob/main/docs/benchmark.md). Reproduce it, or evaluate your own text\nbackend, with `bench/` ([docs/benchmarking.md](https://github.com/danielnc/jev-browse/blob/main/docs/benchmarking.md)).\n\n- [install.md](https://github.com/danielnc/jev-browse/blob/main/install.md) : step-by-step install, written for an agent to follow\n- [docs/architecture.md](https://github.com/danielnc/jev-browse/blob/main/docs/architecture.md) : the decision loop, modules, and safety model\n- [docs/configuration.md](https://github.com/danielnc/jev-browse/blob/main/docs/configuration.md) : every setting\n- [docs/backends.md](https://github.com/danielnc/jev-browse/blob/main/docs/backends.md) : text backends and their trade-offs\n- [docs/benchmarking.md](https://github.com/danielnc/jev-browse/blob/main/docs/benchmarking.md) : running the benchmark and`text_eval`\n- [skill/SKILL.md](https://github.com/danielnc/jev-browse/blob/main/skill/SKILL.md) and[skill/reference.md](https://github.com/danielnc/jev-browse/blob/main/skill/reference.md) : what the agent reads\n\nSee [CONTRIBUTING.md](https://github.com/danielnc/jev-browse/blob/main/CONTRIBUTING.md). Development is offline by default: `uv sync && make check` runs the\nlinter and more than 400 tests with TypeSafe, the CLIs, and Chrome mocked.\n\nMIT, see [LICENSE](https://github.com/danielnc/jev-browse/blob/main/LICENSE). jev-browse ports code from\n[browser-use/jev-ultrafast](https://github.com/browser-use/jev-ultrafast) (MIT, Copyright (c) 2026 Browser Use);\nsee [NOTICE](https://github.com/danielnc/jev-browse/blob/main/NOTICE). Ported files carry a header comment naming the upstream file.", "url": "https://wpnews.pro/news/show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost", "canonical_source": "https://github.com/danielnc/jev-browse", "published_at": "2026-09-24 23:08:04+00:00", "updated_at": "2026-09-24 23:30:43.387623+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["jev-browse", "browser-harness", "TypeSafe Jev", "Claude Code", "Codex", "danielnc", "browser-use/jev-ultrafast", "Chrome"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost", "markdown": "https://wpnews.pro/news/show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost.md", "text": "https://wpnews.pro/news/show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost.txt", "jsonld": "https://wpnews.pro/news/show-hn-jev-browse-browser-sub-tasks-for-coding-agents-at-1-3-the-cost.jsonld"}}