Skip to content

Cost & budget

Only vk ai and vk suite ever call a model. Every other command — tap, text, ui, find, assert, swipe, screenshot, batch, run archive, device set, devices — drives the device directly and costs nothing, ever. They need no API key and have no budget.

Within vk ai, a model is called in exactly two phases, and neither of them is the phase that does the work:

Phase Model calls Bounded by
Compile — prose → plan IR 1 on a cache miss, plus 1 if the plan lint asks for a guided retry --max-cost-usd
Repair — a step’s selector stopped resolving up to 3 per failing step --max-cost-usd, --timeout
Replay — running the plan on the device none — always $0 —

Pay once to compile, replay free, pay again only when the app drifts under a step. See Natural-language tests.

A compile happens when the plan cache misses. Four things cause a miss:

Cause Detail
The cache key changed Key is the test prose byte-exact, plus --package, --app-build and the platform. A reworded sentence is a new key.
The compiler fingerprint rotated verikun’s version plus its grammar and repair-prompt text. A verikun upgrade re-spends the whole suite.
--recompile / --no-cache Skips the read outright.
No cache on disk A fresh CI runner has no ./.verikun/plans/ — see the cold cache.

The lint retry can add a second call: after compiling, verikun checks the plan against the prose, and one finding triggers exactly one guided recompile. It is skipped if the budget is already spent, in which case the first plan is kept rather than paying for a better one.

Two spenders that surprise people:

  • --show-plan still compiles, and still spends. It skips the device, not the model.
  • Seeding from a prior build is still a paid compile. A prior plan goes into the prompt as a starting point, which makes the result better, not the call cheaper.

A repair is triggered only by a selector that misses or resolves ambiguously. It is capped at 3 attempts per failing step — a fixed number with no flag.

An assert failure never heals, so it never costs anything. Neither does an environment error, a guard, or a read. See Self-healing in CI.

Each API response reports its token usage. Every response is priced with the same formula:

(input × in$ + output × out$ + cache_write × in$ × 1.25 + cache_read × in$ × 0.1) ÷ 1,000,000

where in$ and out$ are the model’s price per 1M tokens (where they come from). At an illustrative $3 in / $15 out, a compile with 1,500 input, 2,000 output and 6,000 cache-write tokens costs about $0.057.

Four things about that formula are not visible from the outside:

  • Cache write is 1.25 × the input rate and is added to normal input, so caching pays off only from the second call — and compile and repair use different prefixes.
  • Cache read is 0.1 × the input rate, except gpt-4.1 at 0.25 ×.
  • --effort raises cost through the output rate (reasoning tokens bill as completion tokens); it has no effect on gpt-4.1 or the CLI backends.
  • It is an estimate, and it under-counts: a retried attempt and a response without a usage block both count as zero. The repair cap and --timeout keep that bounded.

Every model carries two numbers: USD per 1M input tokens and USD per 1M output tokens.

The single source of truth is src/agent/cost.ts — read your model’s rate there. The file also records the date each vendor’s prices were captured. For which models exist, which backend serves each, and which key it needs, see AI plans & models.

--max-cost-usd <n>, default $3, aborts the run when the running estimate reaches the ceiling. --timeout <dur>, default 15m, is the second bound.

The budget is a pre-spend gate: it is tested before each further compile of a multi-chunk test, before the lint retry (which is skipped rather than failed), after compile but before the device run, and before each repair attempt. Because the check happens before a call, the actual spend can overshoot the ceiling by up to one call. It is never checked during replay, because replay never spends.

[ai] ABORTED — cost ceiling $3 reached · compile=$3.0142 · repairs=$0.0000 · replay=$0 · cache_read=0 tok · est $3.0142
  • Exit 1 — the same code as an ordinary test failure. There is no distinct budget exit code; abortedForBudget: true in --json is the discriminator. See Exit codes.
  • The run is recorded as failed, so the JUnit and HTML report show it red. A budget abort can never archive green.
  • --retries never retries it — each attempt would get its own fresh ceiling and re-abort.
  • A compile-time abort produces no artifacts at all — no run directory, no report, no JUnit, and therefore empty stdout. Worth knowing if you script REPORT=$(vk ai …).

Every run prints one line in this shape:

compile=$0.0184 · repairs=$0.0000 · replay=$0 · cache_read=12043 tok · est $0.0184
Field Meaning
compile Spend on compiling the prose into a plan, including any lint retry
repairs Spend on model repairs of drifted steps
replay Always $0 — running the plan calls no model
cache_read Cached input tokens read across the run — the only token count printed
est compile + repairs, the figure --max-cost-usd meters

Where the line surfaces:

Surface Where
stderr Appended to the [ai] PASS / [ai] FAIL … / [ai] ABORTED … verdict, then repeated on a completed run as [ai] estimated total cost: $…
vk ai --json cost (the line) and costUsd (the number, 4 dp)
HTML report The vk ai box at the top of the run report
JUnit XML <testsuite><system-out>, prefixed vk ai:. There is no per-<testcase> cost.
Suite overview A Cost column per test, plus the summary chip
Suite index.json totals.costUsd, per-test costUsd, per-attempt costUsd
  • A cache hit. The plan replays with no model call, so the line reads est $0.0000.
  • The CLI backends. --model codex-cli / --model cursor-cli shell out to an already-logged-in codex or cursor-agent, billing your ChatGPT or Cursor subscription rather than per token. They report $0, which also makes --max-cost-usd and --cost-override inert no-ops — the run is bounded by the repair cap and --timeout instead.
Do this Because
Persist ./.verikun/plans/ between CI runs It is the difference between $0 and a full recompile of every test, every run. How
Name identifiers in the prose — Tap @get_started, not “tap the big green button” A selector that resolves never triggers a repair, the only recurring cost on a warm cache.
Assert, don’t just act An assert failure is terminal and never healed, so it fails fast instead of paying for three repair attempts.
Pick a cheaper model, or a CLI backend Compile is output-heavy (the plan is JSON), so the output rate dominates.
Leave --effort alone unless a test needs it It bills through the output rate.
Tighten --max-cost-usd per test It is the cap that always applies; --max-suite-cost-usd is optional.
Expect a full re-spend after upgrading verikun The compiler fingerprint rotates. Budget for it.

This page is about verikun’s own model spend — the compile and repair calls it makes on your behalf. It is not about the tokens your agent spends while driving the device: reading a vk ui dump back into its context, or looking at a screenshot. That is a separate budget, usually the larger of the two, covered in Using it from an AI agent and Screenshots.