This site is available as Markdown for AI agents. For the full index, see llms.txt.
AI-native · MCP-native · local-first

Your agent writes the E2E tests. You review and commit.

unotest is AI-native end-to-end testing. Your AI agent drives your real app over MCP and writes clean, reviewable tests in your repo — for web and for iOS.

Works with Claude Code · Cursor · Codex

Full control

AI does the work. You keep control.

The whole point: speed from the agent, ownership stays with you.

Plain .js in your repo

Tests are ordinary JavaScript in unotest/e2e/*.js. Git, code review, CI — no proprietary format, no binary blob.

No silent fixes

agent_fix composes context and a suggestion — it never calls an LLM itself and never applies a patch on its own. You read the diff and commit.

Runs locally

Everything runs on your machine. Your app never leaves it. No cloud, no account to start.

Safe to run blindly

Scenarios execute in a sandboxed AST interpreter — no require, no fetch, no filesystem. AI-generated tests can run without surprises.

What's new

unotest 0.43.0

Released 27 September 2026.

Spending and deleting wait for a person

A key of your account, a CI key issued before this release included, can no longer rent a box, delete one or switch the Picker on by itself. The cloud records what was asked for and answers with a request instead; somebody approves or declines it in the dashboard, on the Approvals tab, and only a signed-in browser can. Nothing is created and nothing is charged until that happens. For the CLI this is a wait, not a failure. A pipeline that rents or deletes boxes with your key now waits for somebody to press Approve, or has to rent its box ahead of time.

Your cloud account as commands and as MCP tools

An agent can now see and manage the account it works for, not only the box it was pointed at. New commands list your boxes, show the end of a box's own log without logging in to it, and say what is waiting for approval. Nine new MCP tools do the same for an agent, and answer with states it can act on instead of errors: not logged in, waiting for approval, declined.

A config key the package does not know is refused

A misspelled key used to be dropped in silence: the run went ahead on the default, passed and exited 0, so the one setting you changed was the one that did not apply. Every section of the config is now checked by name before the browser starts, and a refusal names the key you probably meant. A config that carries a key this version does not know now fails instead of running: fix the spelling, remove the key, or install the release it belongs to.

A run on an environment no longer inherits a host from the base .env

A project whose base file points an API at production, and whose dev overlay does not mention it, used to run --env dev and send its calls to production without a word. A variable that becomes a host now has to come from the active environment's overlay or from the process environment; otherwise the run is refused before the browser starts, naming the variable and both files. A value meant for every environment is declared once in the config.

Pick your platform

Same idea, two surfaces — the web and iOS.