operating-vitest-agent
How to drive the vitest-agent MCP tools correctly — the non-obvious operational facts (run_tests scoping, why subset runs "fail" coverage, the consoleLeaks signal, the VITEST_AGENT_CONSOLE escape hatc
Files2
View on GitHubSKILL.mdplugin/skills/operating-vitest-agent/SKILL.md
GitHubOperating vitest-agent as an Agent
Read this first when you are an agent driving a project that uses
@vitest-agent/*. It front-loads the handful of facts that otherwise cost
trial-and-error. For the full run_tests reference (scoping, return shape,
coverage-in-subset, the consoleLeaks signal), see
references/running-tests.md.
The facts that save the most time
- Run tests with
run_tests, not Bashvitest.run_testspersists results, classifications, coverage, and history and fires the post-tool-use hooks. Shelling out tovitestbypasses all of that. run_testshas nofilterparameter. Scope withproject(the Vitest project name),files(globs), ortags. An unknown key likefilteris rejected with an error naming the offending key and the accepted params — fix the call and re-run. Theokresult echoes the resolvedscope(project,files,tags) so you can confirm what actually ran.- Subset runs no longer "fail" coverage thresholds (issue #160). A
scoped call (
files,project, ortagssupplied) is detected as partial and the plugin's reporter neutralizes Vitest's nativecoverage.thresholdscheck for that run before it can flip the exit code — thresholds compared against the whole-project denominator are meaningless against a subset of files. Theokresult carriesscopedNote(also folded into the text summary) explaining that thresholds were skipped and how many of the project's test files actually ran; the persistedtest_runs.scopedflag andreport.coverage.scopedreflect the same signal. Full (unfiltered) runs are unaffected — thresholds still enforce and baselines still ratchet. The--coverage.enabled=falseworkaround is no longer needed for this purpose. - Concurrent Vitest runs no longer clobber each other's coverage
temp files (issue #194). Two runs sharing
coverage.reportsDirectoryused torm -rfeach other'scoverage/.tmpmid-run — the v8 provider'sclean: truedefault — producing an unhandled rejection or a silent exit-0 with no summary.run_testswas always isolated (each call gets its ownmkdtempdirectory);AgentPlugin's plain-CLI path (vitest runfrom the terminal or a script) now isolates too, for theagentexecutor only — a human's./coverageoutput and CI's configured directory are never relocated. Two env vars tune it:VITEST_AGENT_COVERAGE_DIR_ISOLATION=off|0|falseopts out entirely (back to the shared, collision-prone directory);VITEST_AGENT_COVERAGE_DIR=<path>pins an explicit directory verbatim (no mkdtemp, no cleanup) so an orchestrator running several agents can point each one at a directory it collects afterward. Persistence (file_coverage, coverage thresholds/trends) is unaffected either way — it reads the in-memory istanbulCoverageMap, never the on-disk report. - Stray
console.*is surfaced byrun_testsas a signal, not raw logs. Theokresult'sreport.consoleLeaksfield lists writes by file with counts, optional per-test attribution, and a truncated sample.total/byFilecount only writes from tests that did NOT fail — writes logged inside a failing test are excluded from the leak signal and summarized separately infromFailingTests, so a red run whose assertion failures route through a console-backed logger doesn't look like a leaking green run.run_testsstill null-routes Vitest's stdout; the signal captures what was printed without forwarding raw log lines into agent context. To see the raw output for a flagged file, run Vitest on the CLI:VITEST_AGENT_CONSOLE=passthrough pnpm test. Details in references/running-tests.md. - Session attribution is recovered for you. The SessionStart hook writes
the
VITEST_AGENT_*identity into the environment and the SDK recovers it — you never set those vars by hand. Beyond identity, the behavioral knobs areVITEST_REPORTER_LOG_LEVEL,VITEST_REPORTER_LOG_FILE,NO_COLOR, and theVITEST_AGENT_CONSOLEoutput override documented below. - Stale counts mean tests were not re-run, not a warm cache. Discovery re-walks per Vitest run; the MCP serves counts from the database.
- Some "leaks" are guardrail tests that assert on their own output. Do not
silence output a test captures and
expects on. - Restart the MCP server after upgrading or rebuilding
@vitest-agent/*. The server is long-lived and runs Vitest in-process, so it keeps the modules it loaded at startup. After an upgrade, or after rebuildingengineorpluginin a vitest-agent checkout, restart the vitest-agent MCP server before the nextrun_tests. Otherwise the run mixes old and new modules and fails with an ESM link error such asdoes not provide an export named ....
Results that lie
- Judge a run by the collected count, never by
0 failedalone. WhencollectedModulesis known and nonzero, the totals line carriesacross N files— a lower N than you expected means files failed to load or were never collected, not that fewer tests existed. 0 tests collectedis a warning, not a pass. The agent-facing render says so explicitly: "0 tests collected. A zero-test run usually means a wrong working directory, a filter that matched nothing, or a load-time error — verify before trusting it."- Suite/hook errors (an
afterAllthrow) and load-time collection failures now fail theAgentReport:failedFilesis non-empty andreasoncoerces to"failed"even when every individualitblock passed. A green summary with a non-emptyfailedFilesmeans the report predates this fix — rerun on a current build. - Each project's
test_runs.reasonis now derived from that project's own report, not the whole-process outcome — one failing project no longer marks every project in atriage_briefas failed."interrupted"still passes straight through as a global outcome (a killed run is killed for everyone). - If stderr shows
vitest-agent: persistence failed — results above were rendered but NOT recorded: <error>, the rendered output you're looking at is real but nothing reached SQLite for that run —test_status/test_historywill not reflect it until the next successful run. - Always invoke vitest from the absolute repo root in the same command
(
cd /abs/repo && pnpm vitest run --project …) — acdfor one tool silently poisons the next command's project filter. - Never pipe a vitest invocation whose exit code you intend to read
(
vitest run … | tailreports tail's exit code, always 0). Userun_tests' structured return, or the JSON reporter'soutputFile, for machine-readable results.
Environment, briefly
You do not configure vitest-agent through environment variables. The
VITEST_AGENT_* vars (chat id, conversation id, agent ids, project dir,
sidecar bin) are attribution plumbing written by the Claude Code plugin's
SessionStart hook and recovered automatically. The vars you might set:
VITEST_REPORTER_LOG_LEVEL/VITEST_REPORTER_LOG_FILE— diagnostic logger (separate from the console reporter).NO_COLOR— disables ANSI color in rendered output.VITEST_AGENT_CONSOLE=<value>— overrides the resolved console mode for the active executor on a CLIvitestrun. Console output inside tests is swallowed by design; this is the escape hatch to see it raw when investigating a file flagged byreport.consoleLeaks. The accepted values are per-executor-slot literal unions (verbatim frompackages/sdk/src/schemas/Common.ts):humanexecutor:passthrough|silent|stream|agentagentexecutor:passthrough|silent|agentciexecutor:passthrough|silent|ci-annotations
A value invalid for the active executor's slot warns to stderr (
[vitest-agent:plugin] ignoring invalid VITEST_AGENT_CONSOLE="…" for <executor> executor—packages/plugin/src/plugin.ts) and is ignored; the plugin falls back to that slot's normal default. This only changes what gets printed —console.loginside a test is still swallowed by design in every mode exceptpassthrough, so assertions (expect(...)), notconsole.log, are the reliable way to read a value out of a probe test.
Where to go next
| You want to… | Read |
|---|---|
| Scope a run, read the return shape, understand coverage-in-subset | references/running-tests.md |
| Read the full console-mode matrix (human prose) | https://vitest-agent.dev/guide/console-modes |
| The human-facing version of this page | https://vitest-agent.dev/guide/operating-as-an-agent |