Your agent decides what
Claude Code, Codex or Cursor writes the outcome it expects in one sentence. No page trees, no locators, no screenshots.
Each Playwright needs their Prima
Your agent describes the check. A cheaper model drives playwright-cli and sends back the verdict.
npx prima-cli
Works with Playwright CLI
Works with your favorite agent
If your agent checks its work in a real browser, most of its tokens go to reading pages. Prima moves that work to a smaller model and hands back the result.
01 · The problem
When Claude Code or Codex checks a change with playwright-cli, it takes a snapshot, reads the ARIA tree, clicks by ref, and snapshots again because the page re-rendered. Each round is a turn on your most expensive model, and every tree stays in context next to your code.
$ npx playwright-cli snapshot
- navigation [ref=e14] … the whole page tree
$ npx playwright-cli click e87
# page re-rendered, e87 is gone
$ npx playwright-cli snapshot
- navigation [ref=e14] … the whole tree, again
$ npx playwright-cli click e91
…
Every line above goes through your main model and stays in its context for the rest of the session.
02 · The handoff
Prima attaches to the browser your agent opened with playwright-cli. Your agent passes one sentence. A small, fast model drives the page, and your agent gets back a short report instead of a browser transcript.
Your agent sends
$ npx prima-cli check "dark theme survives a reload"
Your agent gets back
PASSED · exit 0
used: I.click('Theme'); I.click('Dark'); I.refreshPage()
artifacts: saved to disk
The snapshots, retries and re-renders happened. Your agent just did not have to read them.
03 · Context
ARIA trees, HTML, screenshots and network logs are written to files. Your agent opens them only when a check fails and it needs a closer look. The rest of the time it stays focused on the code it is changing, and the session runs longer before it has to compact.
In your agent's context
PASSED · checkout succeeds
used: I.click('Place order')
artifacts: output/prima/
A few lines, then back to the code.
On disk, read only if needed
04 · Cost
Finding a button in a page tree does not need Opus. Prima runs that loop on a cheap, fast model such as gpt-oss-120b on Groq or OpenRouter. Your frontier model is billed for deciding what to check and for fixing what broke.
Your agent · frontier model
Prima · small model
Fewer turns on the expensive model, and each turn it does take is about your code.
05 · Evidence
Each step comes back with the code Prima ran. A step it could not complete is marked FAIL with the reason. If an outcome was never checked, Prima says so instead of guessing. At the end, one command turns the session into an HTML or Markdown report you can attach to a pull request.
$ npx prima-cli do "open the account menu" "choose Settings" "switch theme to Dark"
Your agent knows which step broke and what the page showed, without opening a single snapshot.
06 · Setup
Nothing changes in how your agent works. It still opens the browser with playwright-cli. You add one line to your agent instructions, or install the prima skill, and it runs npx prima-cli for checks. It learns every command from npx prima-cli --help.
Your agent runs
$ npx playwright-cli open http://localhost:3000
$ npx prima-cli --help
$ npx prima-cli check "a new user can sign up and sees the dashboard"
PASSED · exit 0
You add to AGENTS.md or CLAUDE.md
- Use npx prima-cli for browser checks
Works with Claude Code, Codex, Cursor, OpenCode and any agent that runs shell commands.
← → · swipe
Your agent writes the feature in one pass, then spends twice as long clicking through it with playwright-cli. Here is that session to scale.
One feature, start to finish
15 min
Writes the feature
one continuous pass
Checks it with playwright-cli
snapshot, read, click, ×20
Two thirds of the session is your most expensive model reading page trees and clicking refs. Every one of those tokens stays in its context and is billed at its rate.
Your agent still runs playwright-cli. Prima sits on top of it as a fast subagent, so the expensive model stops clicking and each model does the work it is priced for.
$ npx prima-cli check "the theme setting survives a reload"
### Result
ok: true expectations: PASSED
used: I.click('Theme'); I.selectOption('Dark'); I.reload(); ...
### Steps
1. ok switch the theme to dark I.selectOption('Theme', 'Dark')
2. ok confirm it took effect I.seeInField('#theme', 'dark')
agent: verdict received in one call. moving on. Claude Code, Codex or Cursor writes the outcome it expects in one sentence. No page trees, no locators, no screenshots.
Prima runs the look-and-click loop on playwright-cli with a cheap, fast model. It finds elements and retries after re-renders. None of that reaches your agent.
PASSED or FAILED, the steps taken and the code that worked. Snapshots and screenshots are saved to disk, not sent to your agent.
The execution model runs on any provider
Many browser steps are a multiple-choice question: which link, did it work. Jev answers those in a fraction of a second, for less than the model that drives the browser.
Specialized model by TypeSafe AI
Most models write an answer. Jev makes a decision.
Cheaper and faster. A small model that picks an answer instead of writing one. Clicks and checks it settles skip a call to the model that drives the browser.
Picks, never makes up. Which button to click, whether the check passed: Jev chooses from the options Prima lists. It cannot invent an answer that is not there.
Says when it is unsure. If Jev is not confident about a choice, Prima hands that step to the regular model instead of guessing.
“Is the billing form filled with all values?”
Card holder
Jane Doe
Card number
4242 4242 4242 4242
Expiry
12 / 28
ZIP code
empty
Regular model
“Looking at the form, the card holder, number and expiry are filled in. The ZIP code field appears to be empty, so the form may not be fully…”
A paragraph Prima has to read and interpret. Slower, and every word is billed.
Jev
choice: no
probabilities: yes 0.06 · no 0.94
confidence: 0.94
A typed answer in a fraction of a second. Nothing to parse.
Confidence decides who answers. 0.94 is above Prima's 0.70 bar, so Prima marks the check failed without calling the regular model. Had Jev been unsure, the same question would go to the regular model.
Your agent does the browser work. You only tell it that Prima is there.
Nothing to install: your agent runs it with npx. Connect an AI provider,
then tell your agent about it in
CLAUDE.md or
AGENTS.md.
npx prima-cli npx prima-cli config
Add the skills to your agent. The
prima
skill teaches it every Prima command, so a short request is enough.
npx skills add testomatio/skills claude "check edit works via prima" Prima runs its own models. It cannot use your Claude or Codex subscription, so it needs a separate AI provider and API key.
We recommend OpenRouter.
One key gets you openai/gpt-oss-120b on the fastest hosts, like Groq, Cerebras and SambaNova,
at 500+ tokens per second, and typesafe/jev for decisions. It is billed separately,
but the bill for browser checks stays very low.
Put the key in your agent's config, since the agent is what runs Prima.
~/.claude/settings.json
{
"env": {
"PRIMA_CLI_AI_MODEL": "openrouter/openai/gpt-oss-120b:nitro",
"PRIMA_CLI_DECISION_MODEL": "openrouter/typesafe/jev-1.13",
"OPENROUTER_API_KEY": "your-key"
}
} :nitro asks OpenRouter for its fastest host, which is Groq for this model.
~/.codex/config.toml
[shell_environment_policy.set]
PRIMA_CLI_AI_MODEL = "openrouter/openai/gpt-oss-120b:nitro"
PRIMA_CLI_DECISION_MODEL = "openrouter/typesafe/jev-1.13"
OPENROUTER_API_KEY = "your-key" set is applied after Codex filters the environment, so the key survives even where names with KEY are stripped.
~/.bashrc or ~/.zshrc
export PRIMA_CLI_AI_MODEL=openrouter/openai/gpt-oss-120b:nitro
export PRIMA_CLI_DECISION_MODEL=openrouter/typesafe/jev-1.13
export OPENROUTER_API_KEY=your-key For agents that inherit your shell. In fish, use set -gx in ~/.config/fish/config.fish.
Put it in the CLAUDE.md or AGENTS.md your agent already reads. That is the whole setup.
Your agent reads the rest from --help.
Delegate browser checks to a low-cost model. Same browser, same session, one call instead of twenty round-trips.
The frontier model stops parsing pages. Snapshots and retries stay inside Prima on a low-cost model; the main agent receives only the verdict and the working code.
Any agent that can run a shell command. npx prima-cli --help is the contract: one call per job, plain-text report, exit code 0 or 1.
The model in PRIMA_CLI_AI_MODEL. The tested default is gpt-oss-120b via OpenRouter or Groq. Screenshot judgement uses a separate vision model.
No. Your agent keeps opening the browser with playwright-cli, and Prima attaches to that same browser and session. When the agent already has a verified locator, it can call playwright-cli or npx prima-cli pw directly.