Browser runtime

Demo

Write a goal, get the exact command that runs it, then read what a real run produced. Execution happens on your machine: the runtime drives your browser with your keys, so nothing is sent to mlola.com and no public endpoint can be abused to browse the web.

Example prompts

Click one to load it into the playground. Two of these run on the hosted runner — choose them under Run it live; the others run where their requirements are met. The templates never resolve as written: they show the shape of a goal for your own application.

Your prompt

Run this on your machine

npx @mlola/browser-cli browser run \
  --goal "Download my latest invoice" \
  --url "http://127.0.0.1:4311/billing" \
  --headless --no-human --yes

Providers come from mlola.config.json, .env.local or the shell — check with `mlola browser config show` before running. The first run opens its own Agent Window, and a tab of yours is only borrowed with your approval.

Run a proven task live (not your prompt)

The runner service runs the catalogue task selected below — proven tasks only, because a public runner that accepted a goal or a URL from a visitor would be an open proxy. Your playground prompt above is never sent: it is for you to run on your own machine, with the command composed for you. So the goal you see here may differ from what you typed — that is the design, not a bug.

Runner offline right now, so the recorded run below is what you get. It is the same task, unchanged, captured from a real run.

What a real run looks like

Verbatim output from runs on a developer machine, with the same goal in the playground.

A real site: fetch a file from ftp.gnu.org

goal: Download the file hello-1.3.tar.gz · url: https://ftp.gnu.org/gnu/hello/

What the page looked like when the file link was chosen
step 1 — the file link is observed and chosen
The end state after the download was verified
final — the same page, because a download does not change the DOM. That is why the proof is the download event and the verified artifact, not a screenshot.
→ NAVIGATE https://ftp.gnu.org/gnu/hello/
  ⤓ downloaded hello-1.3.tar.gz
  ✔ verified: download evidence: 1 event(s), 1 artifact
run completed — verification verified · steps 2 in 3.5s
artifacts  a1 hello-1.3.tar.gz (unknown, verified)

maturity check: 3 runs, 3 completed, 2 steps each, artifact verified every time

Headless Chrome, local fixture

goal: Download my latest invoice · url: http://127.0.0.1:4311/billing

→ NAVIGATE http://127.0.0.1:4311/billing (55ms)
step click → 6 (999ms, conf 0.85)
  ⤓ downloaded invoice-2026-08.pdf (invoice)
step done (311ms, conf 0.99)
  ✔ verified: artifact evidence: a1 invoice-2026-08.pdf
run completed — steps 2 in 3.0s · fast path 100% · $0.0000

Your own Chrome, through the extension

goal: Download my latest invoice · url: http://127.0.0.1:4311/billing

browser   your own Chrome via the extension (extension 0.2.5, protocol 1.1)
→ NAVIGATE http://127.0.0.1:4311/billing (63ms)
  ⤓ downloaded invoice-2026-08 (2).pdf (invoice)
  ✔ verified: artifact evidence: a1 invoice-2026-08 (2).pdf
cleanup  closedTabs: ["t18","t19"] · returnedTabs: [] · orphanLocks: [] · errors: []

Jev as the fast path, OpenRouter key only

goal: Download my latest invoice · url: http://127.0.0.1:4311/billing

decisions  2x  openrouter:jev · typesafe/jev-1.13-20260917
run completed — verification verified · steps 2 in 3.7s
artifacts  a1 invoice-2026-08.pdf (invoice, verified)

No TypeSafe key in the environment; --fast openrouter uses the decisions endpoint.

Go further

Want a hosted runner instead? That needs a rate-limited allowlisted service on our side, and the runtime would no longer be using your logins — so the local-first flow stays the default.