v0.1 · MCP server + CLI · MIT

Browser use for coding agents.
3-5x faster than browser-use.

Claude Code, Codex or any MCP client sends a goal. TypeSafe Jev picks the next click or keystroke in about 300 ms. Your agent supplies the text to type, reads the page, and gets control back when jev-ra cannot continue.

Star on GitHub
jev-ra: a zebra stepping out of a browser window
Works with Claude Code Codex Cursor Any MCP client Python CLI
8.5xWikipedia lookup2.7 s vs 23.1 s · median of 5
7.5xGoogle Flights one-way search, verified8.9 s vs 66.4 s · median of 5
4.0xE-commerce sort3.8 s vs 15.1 s · median of 5

jev-ra median of 5 runs vs browser-use 0.13 flash_mode with gemini-3-flash, same Chrome, same OpenRouter key, 2026-09-18. The headline stays at 3-5x because even our median against browser-use's fastest single run is 5.8x / 5.6x / 4.6x. Method and raw rows in BENCHMARKS.md.

Demo

A recorded run, replayed in the page

The browser draws this from the log of one Google Flights run made on 2026-09-18. Each click, typed value and timing comes from that log. It is not a video.

Source: demo.js (a dependency-free SVG replayer) fed by demo-run-flights.json. Raw screen recordings of the benchmark tasks are in assets/demo/.

Loop

How a step works

Each step is five operations. The only network call is one request to Jev with typed questions. jev-ra builds no prompt and generates no text, and model output is never used as a selector or as script.

browser-useflash_mode, gemini-3-flash
5.8 s/step
jev-raJev via OpenRouter
0.7 s/step

Wall time divided by steps on the Wikipedia task (23.1 s / 4 vs 4.3 s / 6, 2026-09-18). A jev-ra step is one decision of about 300 ms plus the page's own load and settle time.

Request

What one request looks like

Jev is a decision model. jev-ra sends the page as state with five typed questions and gets back a chosen option with probabilities and two yes/no answers with confidence. A step costs about $0.00025 and there is no prose to parse.

request · state + questionsPOST /decisions

operation choice CLICK · TYPE_TEXT · SELECT · SCROLL_DOWN · SCROLL_UP · WAIT · DONE · BLOCKED
click_target choice [e3] link "신상품순" · [e4] link "판매순" · [e9] button "장바구니" · …
value_for_field choice origin: "Zurich" · destination: "London" · none
prev_ok noul Did the previous action have its intended effect on this page?
goal_achieved noul Is every requirement of the goal visibly satisfied on this page?
state: { page: {url, title, text ≤ 6000 chars}, elements[≤ 250], recent_actions[≤ 10], goal, values_available }

answers · 312 mstypesafe/jev-1.13

operationCLICK p=0.91
click_target[e3] link "신상품순" p=0.87
value_for_fieldnone
prev_oktrue 0.94
goal_achievedfalse 0.12
→ act: click e3 (guard ok, hit-test ok) · verify: text changed, page_changed=true · next step

Question ids and instruction texts are the ones in jev_ra/decide/questions.py; the answers shown are an example. Values your agent passes are chosen by name; jev-ra does not invent strings to type.

Architecture

Architecture

Your agent talks to jev-ra over MCP (stdio). jev-ra drives Chrome over the DevTools Protocol and calls Jev over HTTPS once per step.

Your agent plans · supplies values reads with browser_extract jev-ra pip · npm · uvx MCP server · CLI browser_run · search · extract · act · 10 more Engine agent loop: observe → decide → act → verify action space + policy: offered ops, guards, loop detection values binding · escalation contract · budgets jev_ra/agent.py · decide/policy.py · decide/questions.py Browser core snapshot.js in one Runtime.evaluate · trusted Input events jev_ra/browser/session.py · snapshot.js TypeSafe Jev decision model · System One via OpenRouter or direct jev-1.13 · HTTP/2 Chrome your profile or a managed one 1280×900 · focus emulation DevTools Protocol MCP · stdio goal · values result | escalate state + questions answers · ~300 ms CDP · ws:// snapshot · input One process per box; no queue, daemon, vector store or second model.
Why there are no screenshotsThe snapshot is text and an element table, so a step sends a few KB and Jev answers in about 300 ms. A screenshot tool exists for pages where text is not enough.
Why the model never touches the DOMEvery target is an observed node id. Before input, jev-ra re-checks the element's identity guard and hit-tests its geometry; a covered or changed control returns stale instead of a wrong click.
What your agent still doesPlanning, supplying text values, and reading the page. jev-ra executes one concrete goal and returns the page with candidates when it cannot continue.

Escalation

When a run stops early

A run that cannot finish returns one of eight reasons, the top candidates and the page text, so the agent can act without observing again.

needs_valuea field needs a string you did not supply. Add it to values, call again.
stuck_loopthree steps, no page change. Read the text, click one candidate, continue.
unverified_doneJev says done, no visible proof. Check with browser_extract.
stalethe page kept changing under it. browser_wait(), retry once.
budgetsteps or time ran out. Narrow or split the goal.
too_many_controlsover 250 controls in view. Scroll or open the section first.
blockedlogin, captcha, empty results. Tell the user; do not retry blindly.
invalid_decisionan answer not on the page, twice. Re-observe and drive one step yourself.

Benchmarks

Benchmarks

jev-ra bench --live reproduces every number below: browser-use and jev-ra in the same Chrome with the same key.

Taskbrowser-use flash_modebrowser-use defaultjev-raratio
Wikipedia: open the Gödel incompleteness article23.1 s · 4 steps46.5 s · 5 steps2.7 s · 2 steps8.5x
Google Flights ZRH→LON one-way, 7 checks verified66.4 s · 11 steps63.6 s · 11 steps8.9 s · 11 steps7.5x
Olive Young category: sort by newest15.1 s · 3 steps17.5 s · 3 steps3.8 s · 2 steps4.0x

jev-ra columns are medians of 5 runs (5/5 success each); browser-use columns are the single baseline runs, and its own 5-run medians are slower (24.6 s / 73.8 s / 27.6 s). BENCHMARKS.md carries p90, cost per task and the per-step time breakdown.

Install

Install

An OpenRouter key is enough; no TypeSafe account is needed. jev-ra doctor checks the key, Chrome and one live decision.

export OPENROUTER_API_KEY=sk-or-...
uvx jev-ra install claude
uvx jev-ra doctor
# then in Claude Code: "search the web for X and summarise"

If an agent installs this for you, point it at AGENTS.md: install steps, the tool table, what to do on each escalation, and cost.

Limits

Limits

These return an escalation with a reason.

Out of scope in v0.1

  • Cross-origin iframes (same-origin and open shadow roots work)
  • Canvas-drawn UIs
  • File uploads
  • Captchas, bot walls
  • Multi-tab workflows

By design

  • Types only values your agent supplied; personal data is never guessed
  • Model output is never used as a selector or as JavaScript
  • Done is reported only after a visible check
  • Jev receives visible page text, not file bodies or screenshots