
Vitest Evals
- 31 installs
- 325 repo stars
- Updated July 23, 2026
- getsentry/vitest-evals
vitest-evals skill documents Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing norm
About
vitest-evals skill documents Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing normalized run data, or examples and docs for these APIs.. name: vitest-evals description: Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing normalized run data, or examples and docs for these APIs.
- Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-
- Platform-specific setup patterns for vitest-evals.
- Evidence-backed steps from upstream SKILL.md.
- When-to-use criteria for vitest-evals versus alternatives.
Vitest Evals by the numbers
- 31 all-time installs (skills.sh)
- Ranked #665 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
vitest-evals capabilities & compatibility
- Capabilities
- vitest evals quick start · vitest evals when to use guidance · vitest evals integration patterns
- Works with
- sentry
- Use cases
- code review
What vitest-evals says it does
Use the harness-backed API as the only authoring model.
1. Read the package, app, or eval file being changed.
npx skills add https://github.com/getsentry/vitest-evals --skill vitest-evalsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 31 |
|---|---|
| repo stars | ★ 325 |
| Last updated | July 23, 2026 |
| Repository | getsentry/vitest-evals ↗ |
How do I use vitest-evals correctly?
Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing normalized ru
Who is it for?
Teams implementing vitest-evals workflows from the catalog.
Skip if: Skip when requirements clearly match a different specialized stack.
When should I use this skill?
User asks about vitest-evals, use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom har.
What you get
Working vitest-evals setup with validated configuration and next steps.
Files
vitest-evals
Use the harness-backed API as the only authoring model.
First Steps
1. Read the package, app, or eval file being changed. 2. Identify the runtime target, then open only the needed reference. 3. Keep suites close to Vitest: one harness per describeEval(...), explicit run(...) inside each test, ordinary expect(...) assertions over the returned result.
Reference Router
| Need | Open |
|---|---|
| Write or review a normal eval suite | references/suite-authoring.md |
Build a custom app Harness without a first-party adapter | references/custom-harness.md |
Integrate AI SDK generateText, generateObject, tools, or an AI SDK-style agent | references/harness-ai-sdk.md |
| Integrate a Pi AI or Pi Mono-style agent | references/harness-pi-ai.md |
Add custom judges, suite judges, built-in judges, or toSatisfyJudge(...) assertions | references/judges-and-assertions.md |
| Assert on message, tool-call, or span history | references/utilities.md |
| Configure tool recording or replay | references/tool-replay.md |
| Diagnose failures, missing traces, odd output, or choose verification commands | references/troubleshooting.md |
Runtime Defaults
- Import
describeEval(...), judges, and helpers fromvitest-evals. - Bind exactly one
harnessto a suite. - Call
run(input)where the test should execute the system. - Assert on
result.outputfor app-facing behavior. - Use
toolCalls(result)and message helpers for normalized session assertions. - Use
spans(result),spansByKind(result, kind), andfailedSpans(result)for span assertions. - Keep
HarnessRun,NormalizedSession, usage, artifacts, and tool records JSON-serializable. - Keep judge model calls on judges. Use
createJudge("Name", assess)for
custom judges; use the provider-helper overload only when multiple judges reuse setup and need curried run options.
- Put scenario-owned criteria on the input value. Put direct-check expected
values in Vitest case rows. Pass per-case judge criteria through explicit matcher options, and suite-wide criteria through judge config.
- Custom judges should use
createJudge(...)for stable reporter labels.
Verification
Prefer the smallest command that covers the edited files:
| Task | Command |
|---|---|
| Lint file | pnpm exec biome lint path/to/file.ts |
| Format file | pnpm exec biome format --write path/to/file.ts |
| Test file | pnpm exec vitest run path/to/file.test.ts -c vitest.config.ts |
| Eval file | pnpm exec vitest run path/to/file.eval.ts -c vitest.config.ts --reporter=./packages/vitest-evals/src/reporter.ts |
| Type surface | pnpm typecheck |
| Package build | pnpm build |
vitest-evals Skill
Install the whole skills/vitest-evals directory as one skill. Keep SKILL.md, SPEC.md, SOURCES.md, and references/ together because runtime instructions use relative reference paths.
This skill is intentionally focused on the harness-backed vitest-evals API: suite authoring, custom harnesses, first-party AI SDK and Pi AI harnesses, judges, replay, normalized run data, and targeted verification.
Custom Harness
Open this when no first-party harness adapter fits the application runtime.
Contract
import {
normalizeContent,
normalizeMetadata,
toJsonValue,
type Harness,
type HarnessRun,
} from "vitest-evals/harness";
const appHarness: Harness<AppInput, AppOutput> = {
name: "app",
run: async (input, context): Promise<HarnessRun<AppOutput>> => {
const appResult = await runApp(input, {
signal: context.signal,
});
const output = toJsonValue(appResult.decision);
return {
output,
session: {
messages: [
{ role: "user", content: normalizeContent(input) },
{
role: "assistant",
content: normalizeContent(appResult.reply),
metadata: normalizeMetadata({ channel: appResult.channel }),
},
],
metadata: normalizeMetadata({ caseId: appResult.caseId }),
},
usage: appResult.usage ?? {},
errors: [],
};
},
};Required Fields
| Field | Requirement |
|---|---|
name | Stable short label shown in reporter output. |
run | Executes the application once and returns a normalized HarnessRun. |
session.messages | JSON-safe user, assistant, and tool trace. |
usage | Empty object when unknown; include provider/model/tokens when available. |
errors | Empty array on success; serialized error records on partial results. |
Implementation Rules
- Run the app through its normal entrypoint.
- Inject
context.signaland test doubles where the app supports them. - Use
context.setArtifact(name, value)for JSON-safe diagnostics that should appear on the run. - Convert unknown values with
toJsonValue(...),normalizeContent(...), ornormalizeMetadata(...). - Attach a partial run to thrown errors with
attachHarnessRunToError(...)when meaningful trace data exists. - Put text that should be judged as text in
run.output; put transcript text in assistant messages.
Choose A Custom Harness When
| Runtime shape | Why |
|---|---|
| Full product workflow | The app has events, side effects, or domain output beyond a provider result. |
| Non-AI-SDK provider | First-party adapters cannot infer provider steps or tool calls. |
| Existing observability seam | App emits messages or tool records you can normalize directly. |
| Multi-service workflow | A thin adapter can preserve the real app boundary while normalizing one run. |
AI SDK Harness
Open this for ai package integrations such as generateText, generateObject, tools, or AI SDK-style agents.
Install And Import
npm install -D ai vitest-evals @vitest-evals/harness-ai-sdkimport { aiSdkHarness, type AiSdkToolset } from "@vitest-evals/harness-ai-sdk";Default generateText Pattern
import { generateText, stepCountIs } from "ai";
const harness = aiSdkHarness({
tools,
run: ({ input, runtime }) =>
generateText({
model,
prompt: input,
tools: runtime.tools,
stopWhen: stepCountIs(5),
temperature: 0,
}),
output: ({ result }) => parseDomainOutput(result.text),
});Options
| Option | Requirement |
|---|---|
run | Use for custom execution such as generateText(...); mutually exclusive with agent. |
agent | Use for objects or per-run factories exposing run(input, runtime) or generate(input, runtime); mutually exclusive with run. |
tools | Optional AI SDK toolset; wrapped before being passed to the run callback or agent. |
output | Optional typed domain output selector for raw provider results; default provider output checks output, object, experimental_output, then text. |
name | Optional reporter label; defaults to ai-sdk. |
Agent factories receive { input, context } before execution so apps can derive instructions or seeded state without side-channel setup.
When LLM-backed judges need shared provider setup, keep that helper in the judge module. Do not put judge-model calls on the app harness:
const verdict = await generateText({
model: rubricModel,
prompt: formatJudgePrompt(ctx),
}).then((result) => result.text);Normalization Behavior
- Reads
stepsto build assistant messages, tool calls, tool results, and metadata. - Reads
totalUsageorusage; if absent, aggregates step usage where available. - Preserves provider and model from the last step when present.
- Uses
result.sessionorresult.tracedirectly when they already matchNormalizedSession. - Adds runtime tool calls that were executed through wrapped tools but did not appear in provider steps.
- Attaches partial runs to thrown errors so failed executions can still expose tool traces.
Tool Rules
- Define tool inputs and outputs so they can be normalized to JSON.
- Set
replay: trueor a replay config only on tools withexecute(...). - Provider-executed tools without
execute(...)cannot be recorded automatically. - Replay rejects async iterable tool outputs; return JSON-safe values for recorded tools.
Use Cases
| Case | Prefer |
|---|---|
Direct generateText(...) or generateObject(...) call | run |
Existing app wrapper with run(input, runtime) | agent |
| Provider result text needs parsing | output |
| App returns a full normalized run | Return HarnessRun. |
| App needs exact session/usage/errors control | Return HarnessRun. |
Pi AI Harness
Open this for Pi AI or Pi Mono-style agents.
Install And Import
npm install -D vitest-evals @vitest-evals/harness-pi-aiimport { piAiHarness, type PiAiRuntime, type PiAiToolset } from "@vitest-evals/harness-pi-ai";Default Agent Pattern
const harness = piAiHarness({
agent: () => createRefundAgent(),
});agent can be an existing agent instance or a per-run factory. Factories receive { input, context } when per-run instructions, native tool closures, or seeded artifacts are needed before instrumentation.
If the agent needs a custom entrypoint:
const harness = piAiHarness({
agent: () => createRefundAgent(),
run: ({ agent, input, runtime }) => agent.execute(input, runtime),
});Options
| Option | Requirement |
|---|---|
agent | Existing instance or factory for a fresh per-run agent; factories receive { input, context }. |
run | Optional custom execution; omitted when the agent exposes run(input, runtime). |
tools | Optional explicit PiAiToolset; use when the agent hides its tool surface. |
output | Optional typed domain output selector for provider/custom results that do not already return output. |
name | Optional reporter label; defaults to pi-ai. |
Runtime Surface
run receives { agent, input, context, runtime }.
| Runtime field | Use |
|---|---|
runtime.tools | Wrapped tool functions that record tool calls and replay metadata. |
runtime.events.system(...) | Add a normalized system message. |
runtime.events.user(...) | Add a normalized user message. |
runtime.events.assistant(...) | Add the final assistant text or structured assistant content. |
runtime.events.tool(...) | Add a tool message when the native agent produced one. |
runtime.signal | Forward cancellation to the app when supported. |
Tool Inference
- The harness looks for runtime toolsets on the agent and nested
agent,state, orinitialStateobjects. - It also instruments native tool arrays with
{ name, execute }. - Instrumentation is restored after a run and reapplied after agent resets.
- Explicit
toolsoverrides runtime tools but native tool tracing can still be captured.
Normalization Behavior
- Starts sessions with a user message for the input.
- Uses recorded runtime events as normalized messages.
- Adds tool calls from wrapped runtime tools and native tool instrumentation.
- Reads usage from
usageormetrics, and adds tool call counts when absent. - Uses
result.sessionorresult.tracedirectly when they already matchNormalizedSession. - Attaches partial runs to thrown errors.
Use Cases
| Case | Prefer |
|---|---|
Conventional agent with run(input, runtime) | agent |
| Existing agent method named differently | Add run |
| Hidden tool surface | Add explicit tools |
| Wrapped result with domain object | Add output |
| Agent produces extra messages | Use runtime.events.* inside the app run path |
Judges And Assertions
Open this when adding or reviewing judges, suite-level scoring, or explicit toSatisfyJudge(...) assertions.
Judge Context
Every judge receives:
| Field | Meaning |
|---|---|
input | Original typed eval input. |
output | Typed app output returned by the harness. |
toolCalls | Flattened calls from the run. |
run | Full normalized HarnessRun. |
session | Normalized session from the run. |
harness | Suite harness for intentional second runs. |
Custom Judge Pattern
import {
createJudge,
} from "vitest-evals";
const RefundRubricJudge = createJudge<
string,
RefundOutput,
{ expectedStatus: string }
>(
"RefundRubricJudge",
async (ctx) => {
const verdict = await callJudgeModel({
prompt: formatRubric({
input: ctx.input,
output: ctx.output,
expectedStatus: ctx.expectedStatus,
}),
});
return parseVerdict(verdict);
},
);Automatic Vs Explicit
| Need | Use |
|---|---|
Every run(...) in a suite must be scored the same way | Suite judges: [Judge] |
| A score below a threshold should fail the test | judgeThreshold or matcher threshold |
| Record a score without failing | threshold: null |
| Only one assertion needs the judge | await expect(result).toSatisfyJudge(Judge) |
| Judge needs structured app output | Type JudgeContext<..., TOutput> and read ctx.output |
| Judge needs text | Use a text TOutput or explicitly project structured output to text |
| Judge needs shared model setup | Keep a local helper in the judge module, or use the provider-helper overload of createJudge(...) when curried run options are needed |
Built-In Judges
| Judge | Use |
|---|---|
FactualityJudge({ judgeHarness, expected }) | Model-grade normalized output against suite-wide expected text. |
ToolCallJudge({ expectedTools }) | Check suite-wide expected tool names or arguments. |
StructuredOutputJudge({ expected }) | Check suite-wide expected fields against run.output. |
Matcher Context Rules
expect(result).toSatisfyJudge(...)reuses the fixture-backed run context.expect(result.output).toSatisfyJudge(...)can reuse the exact run when the output object came from that run.- Raw values outside an eval context need explicit
input,session,run,
harness, or custom judge params when the judge depends on them.
- Normalized sessions infer output from the latest assistant message content.
- Calling
ctx.harness.run(...)inside a judge executes the app again; only do this when the judge intentionally needs a second run.
Review Checklist
- Custom judges should usually use
createJudge("Name", assess). - Scores are numbers or
null; failure behavior is controlled by thresholds. - Rationale or parsed judge output is placed under
metadata. - LLM-backed judges provide the judge prompt/rubric text. Shared provider setup
belongs in a judge-side helper, not on the app harness.
Suite Authoring
Open this when writing or reviewing a normal harness-backed eval suite.
Required Shape
import { expect } from "vitest";
import { describeEval, toolCalls } from "vitest-evals";
describeEval("refund agent", { harness }, (it) => {
it("approves a refundable invoice", async ({ run }) => {
const result = await run("Refund invoice inv_123");
expect(result.output).toMatchObject({ status: "approved" });
expect(toolCalls(result).map((call) => call.name)).toEqual([
"lookupInvoice",
"createRefund",
]);
});
});Suite Rules
| Rule | Why |
|---|---|
Use one harness per describeEval(...) suite. | Core stores one normalized run per explicit execution. |
Call run(...) inside the test body. | The test controls when the system under test executes. |
Assert domain behavior on result.output. | Harnesses preserve app-facing results separately from trace data. |
Assert trace behavior with helpers such as toolCalls(result) and spansByKind(result, "tool"). | Reporter, replay, tools, spans, and judges consume normalized run data. |
| Keep expected values in the Vitest row or matcher options. | Case criteria stays close to the assertion that uses it. |
Use it.for(...) for case tables. | Keep table-driven suites idiomatic Vitest. |
Core Options
| Option | Use |
|---|---|
harness | Required runtime adapter for the suite. |
judges | Optional automatic judges after each successful run(...). |
judgeThreshold | Optional fail threshold for automatic judges; null records without failing. |
skipIf | Optional environment gate for provider-dependent suites. |
Normalized Run Checklist
run.outputis JSON-serializable or omitted.run.session.messagescontains user, assistant, and tool records worth reporting.run.usageincludes provider/model/token/tool data when available.run.artifactscontains only JSON-safe diagnostics set throughcontext.setArtifact(...).run.errorsis an array, even on success.
Reporter Setup
For direct eval file runs, include the custom reporter:
pnpm exec vitest run path/to/file.eval.ts -c vitest.config.ts --reporter=./packages/vitest-evals/src/reporter.tsTool Replay
Open this when configuring or debugging tool recording and replay.
Vitest Env
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
env: {
VITEST_EVALS_REPLAY_MODE: "auto",
VITEST_EVALS_REPLAY_DIR: ".vitest-evals/recordings",
},
},
});Modes
| Mode | Behavior |
|---|---|
auto | Replay when a recording exists, otherwise call live and write one. This is the default. |
record | Always call live and overwrite the recording. |
off | Never read or write recordings. |
strict | Require an existing recording and fail when missing. |
Tool Opt-In
AI SDK:
const tools = {
lookupInvoice: {
replay: true,
inputSchema,
execute: lookupInvoice,
},
};Pi AI:
const tools = {
lookupInvoice: {
replay: true,
execute: lookupInvoice,
},
};Replay Config
Use an object when the default cache key or recording needs adjustment:
replay: {
version: "v2",
key: (args) => ({
args,
tenant: args.tenant,
}),
sanitize: (recording) => ({
...recording,
metadata: undefined,
}),
}Recording Rules
- Recordings live under
<replay-dir>/<tool-name>/<cache-key>.json. - Cache keys include tool name, normalized key input, and optional version.
- Inputs and outputs must be JSON-serializable.
- Tool errors are recorded and replayed as errors.
- Replay metadata is attached to tool call metadata as
metadata.replay. - Recorded metadata includes
status,recordingPath, andcacheKey.
Harness Notes
| Harness | Notes |
|---|---|
| AI SDK | Replay only wraps tools with execute(...); provider-executed tools cannot be recorded automatically. |
| Pi AI | Replay works for explicit runtime tools and instrumented native tool arrays. Native tool recordings preserve both agent-facing and normalized results. |
| Custom harness | Call executeWithReplay(...) from vitest-evals/replay directly if replay should be part of the adapter. |
Troubleshooting
Open this for failing evals, missing reporter data, or uncertain verification.
Failure Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
Test has no run fixture | Suite is not inside describeEval(...). | Wrap the suite with describeEval(name, { harness }, (it) => { ... }). |
| App executes more than once per test | Judge or assertion calls the app directly. | Use the returned result; reserve harness.run(...) inside a judge for intentional second runs. |
| Reporter shows little harness detail | HarnessRun.session, usage, or errors is sparse. | Return a richer normalized run with assistant messages. |
| Tool calls are missing | Tools were not passed through the harness runtime or native tool inference missed them. | Use wrapped runtime.tools, explicit tools, or emit events from the app seam. |
| Tool arguments/results disappear | Values are not JSON-serializable or normalize to undefined. | Convert to records, arrays, strings, numbers, booleans, or null. |
| Judge receives blank text | The judge expects text but the run output or assistant content is not text. | Use a text run.output or project structured output to text inside the judge. |
| Structured output judge fails unexpectedly | run.output is not the parsed domain object. | Return { output } from run(), or add an output selector when returning a raw provider result. |
| Replay misses an existing recording | Cache key input, version, tool name, or replay dir changed. | Inspect metadata.replay.recordingPath and update key or version. |
strict replay fails | Recording does not exist for the current key. | Run auto or record once, or commit the expected recording. |
| Replay rejects a tool output | Tool returned a non-JSON value or async iterable. | Return JSON-safe values from recorded tools. |
| Failed run loses trace data | Error was thrown without an attached partial run. | First-party harnesses attach partial runs; custom harnesses should use attachHarnessRunToError(...). |
| Provider-dependent eval is skipped locally | Missing API key or app env. | Keep skipIf explicit and run deterministic unit tests for adapter logic. |
Verification Map
| Change | Minimum useful command |
|---|---|
| One eval file | pnpm exec vitest run path/to/file.eval.ts -c vitest.config.ts --reporter=./packages/vitest-evals/src/reporter.ts |
| Core harness or judge API | pnpm exec vitest run packages/vitest-evals/src/harness.test.ts -c vitest.config.ts |
| Reporter formatting | pnpm exec vitest run packages/vitest-evals/src/reporter.test.ts -c vitest.config.ts |
| AI SDK harness | pnpm exec vitest run packages/harness-ai-sdk/src/index.test.ts -c vitest.config.ts |
| Pi AI harness | pnpm exec vitest run packages/harness-pi-ai/src/index.test.ts -c vitest.config.ts |
| Public type surface | pnpm typecheck |
| Package output | pnpm build |
Review Checklist
- New exported functions have brief JSDoc when code is added.
- Docs and examples use the same import paths as package exports.
- Provider-key-dependent evals are gated with
skipIf. - Test assertions cover output, tool traces, and usage when the change affects them.
- Normalized data can be serialized with
JSON.stringify(...).
Utilities
Open this when assertions need normalized message, tool-call, or span history.
Session Helpers
Use these helpers with a HarnessRun such as result. They also accept a normalized session when that is the only value available.
| Helper | Use |
|---|---|
toolCalls(result) | Flatten tool calls from normalized messages. |
assistantMessages(result) | Read assistant transcript turns. |
userMessages(result) | Read user transcript turns. |
systemMessages(result) | Read system transcript turns. |
toolMessages(result) | Read tool transcript turns. |
messagesByRole(result, role) | Read messages for any normalized role. |
latestAssistantMessageContent(result) | Read the latest non-empty assistant content. |
const calls = toolCalls(result);
expect(calls.map((call) => call.name)).toEqual([
"lookupInvoice",
"createRefund",
]);
expect(latestAssistantMessageContent(result)).toContain("approved");Trace Helpers
Use these helpers with a HarnessRun such as result when behavior is represented by spans. They also accept a normalized trace array when that is the only value available.
| Helper | Use |
|---|---|
spans(result) | Flatten every span from a run. |
spansByKind(result, kind) | Filter spans by run, model, tool, or another span kind. |
failedSpans(result) | Read spans with error status or normalized errors. |
expect(spansByKind(result, "tool").map((span) => span.name)).toContain(
"lookupInvoice",
);
expect(failedSpans(result)).toHaveLength(0);vitest-evals Skill Sources
Synthesis Summary
| Field | Decision |
|---|---|
| Operation | create new installable repo skill |
| Skill class | integration-documentation |
| Primary shape | reference-backed-expert |
| Secondary shape | none |
| Simplicity rationale | One inline file would bury harness-specific details; scripts are unnecessary because the work is authoring and review guidance. |
| Portability | Uses only relative bundled references and repo commands; no provider-specific skill mechanics. |
Source Inventory
| Source | Trust | Confidence | Contribution | Usage constraints |
|---|---|---|---|---|
docs/architecture.md | high | high | core harness lifecycle, normalized run/session model, package boundaries | Use only current harness-backed guidance. |
docs/development-guide.md | high | high | package ownership, workflow, documentation expectations | Keep repo-specific commands aligned with AGENTS.md. |
docs/testing.md | high | high | targeted test expectations for root, reporter, harness, and demo changes | Use narrow verification first. |
packages/vitest-evals/README.md | high | high | install, core model, custom harnesses, judge matcher behavior | Use the core, custom harness, and matcher sections only. |
packages/vitest-evals/src/index.ts | high | high | describeEval, run(...), automatic judges, matcher context behavior | Runtime API source of truth. |
packages/vitest-evals/src/harness.ts | high | high | Harness, HarnessRun, normalization helpers, session helpers | Runtime type source of truth. |
packages/vitest-evals/src/judges/* | high | high | judge context, built-in judge options, judge result metadata behavior | Keep examples judge-first. |
packages/vitest-evals/src/replay.ts | high | high | replay modes, env vars, recording shape, cache key behavior | Use for shared replay guidance. |
packages/harness-ai-sdk/README.md and src/index.ts | high | high | AI SDK harness options, output selection, replay constraints | Keep option names exact. |
packages/harness-ai-sdk/src/index.test.ts | high | high | edge cases for agent/run entrypoints, partial runs, output and tool normalization, replay errors | Use as failure/workaround evidence. |
packages/harness-pi-ai/README.md and src/index.ts | high | high | Pi harness options, tool inference, event sink, output selection, replay | Keep option names exact. |
packages/harness-pi-ai/src/index.test.ts | high | high | edge cases for native tools, reset, inferred tools, output selectors, partial runs, replay | Use as failure/workaround evidence. |
apps/demo-ai-sdk/evals/* and apps/demo-ai-sdk/evals/shared.ts | medium | high | realistic AI SDK suite shape and output parsing | Treat provider keys as app-local setup. |
apps/demo-pi/evals/* and apps/demo-pi/src/refundAgent.ts | medium | high | realistic Pi suite shape, runtime seam, event use, tool assertions | Treat provider keys as app-local setup. |
| package manifests | high | high | package names, peer dependency ranges, workspace commands | Refresh when releases change. |
Decisions
| Decision | Status | Evidence |
|---|---|---|
Put skill under skills/vitest-evals | adopted | User requested this path; no existing repo skill tree conflicted. |
| Use reference-backed layout | adopted | First-party harnesses have distinct options and failure modes. |
| Add one reference per supported harness path | adopted | Supported paths are custom Harness, AI SDK harness, and Pi AI harness. |
| Add shared judge, utilities, and replay references | adopted | First-party harnesses feed the same judge, helper, and reporter APIs; replay is implemented centrally. |
| Omit install scripts | deferred | A self-contained skill directory is enough now; no repo skill catalog or installer exists. |
| Avoid alternate suite API guidance | adopted | User asked for the skill to stay purely harness-backed. |
Coverage Matrix
| Dimension | Status | Coverage |
|---|---|---|
| API surface and behavior contracts | covered | describeEval, run, Harness, HarnessRun, JudgeContext, first-party harness options, utilities, replay. |
| Config/runtime options | covered | suite options, harness options, replay env vars, package peer ranges. |
| Downstream use cases | covered | new eval suite, table-driven cases, custom app harness, AI SDK generateText, AI SDK agent entrypoint, Pi agent default run, Pi custom run, native Pi tools, LLM-backed judge, deterministic tool/output judge, session helpers, trace helpers, replayed tools. |
| Issues and workarounds | covered | troubleshooting reference includes missing harness, duplicate executions, missing tool traces, non-JSON data, replay misses, provider-executed tools, async iterable replay outputs, hidden Pi tools, reset behavior, blank judge output, and missing provider keys. |
| Version variance | partial | Peer ranges are captured from package manifests; future package releases should refresh option tables before release-sensitive edits. |
| Reference discoverability | covered | Every runtime reference is directly routed from SKILL.md. |
Trigger Optimization
Should trigger:
- "write a vitest-evals suite for my refund agent"
- "wire an ai-sdk generateText app into vitest-evals"
- "make a pi-ai harness eval"
- "add a custom judge using JudgeContext"
- "why are tool calls missing from my vitest-evals reporter output?"
- "configure vitest-evals replay"
- "create docs for harness-backed vitest-evals"
Should not trigger:
- "write a generic Vitest unit test"
- "optimize this model prompt"
- "create a spreadsheet of eval results"
- "build a React dashboard"
- "debug Anthropic authentication outside the eval harness"
- "write a generic AI SDK tutorial"
Final description: Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing normalized run data, or examples and docs for these APIs.
Retrieval Stopping Rationale
Source coverage includes package docs, source types, first-party harness implementations, harness tests, demo evals, replay code, and repo policy docs. Additional retrieval is low-yield until API options, package names, or repo installation conventions change.
Open gaps
- Review
skills,.agents, plugin manifests, and repo install docs before adding any registration file. - Confirm future repo docs or skill installer conventions before adding an install script or catalog entry.
- Retrieve package manifests plus
packages/*/src/index.tsbefore changing version-sensitive guidance.
Changelog
- Created initial self-contained
vitest-evalsskill with harness-specific references and shared authoring guidance.
vitest-evals Specification
Intent
This skill helps agents author, review, and debug harness-backed vitest-evals work without needing to rediscover the package shape from source every time. It is optimized for product API correctness, trace quality, and small targeted verification.
Scope
In scope:
- harness-backed eval suites using
describeEval(...) - custom
Harnessadapters - first-party
@vitest-evals/harness-ai-sdkand@vitest-evals/harness-pi-ai - judges, explicit judge matchers, reporter-facing normalized data, and replay
- examples, docs, tests, and package work that changes those APIs
Out of scope:
- unrelated Vitest test authoring
- provider SDK setup that is not part of a harness
- broad application design outside the runtime seam being evaluated
- alternate suite APIs outside the harness-backed model
Users And Trigger Context
- Primary users: coding agents working in this repo or in apps adopting the package.
- Common user requests: create an eval, wire an AI SDK app, wire a Pi agent, add a judge, add replay, debug missing tool calls, document harness usage.
- Should not trigger for: generic unit tests, generic prompt writing, spreadsheet or slide work, or frontend-only tasks.
Runtime Contract
- Required first actions: inspect the touched code, choose the runtime target, open the matching reference.
- Required outputs: implementation or review guidance that uses the harness-backed API only, plus targeted verification.
- Non-negotiable constraints: normalized run data remains JSON-serializable,
suite tests call run(...) explicitly, and judge model calls stay on judges or judge-side helpers rather than the app harness.
- Expected bundled files loaded at runtime:
SKILL.mdfirst, then one or more focused files underreferences/.
Source And Evidence Model
Authoritative sources:
- package source and tests under
packages/vitest-evals - first-party harness source and tests under
packages/harness-ai-sdkandpackages/harness-pi-ai - demo evals under
apps/demo-ai-sdkandapps/demo-pi - repo docs that describe the harness-backed product shape
Useful improvement sources:
- positive examples: demo evals, passing harness tests, reviewer-approved docs
- negative examples: review feedback, test failures, reporter regressions
- commit logs/changelogs: use when API behavior has changed recently
- issue or PR feedback: use when it clarifies user-facing ergonomics
- eval results: use when examples or reporter output drift
Data that must not be stored:
- secrets
- customer data
- private URLs or identifiers not needed for reproduction
- raw provider transcripts unless redacted and required for a reproducible example
Reference Architecture
SKILL.mdcontains activation rules, routing, defaults, and verification commands.references/contains focused runtime lookup files by authoring need.SOURCES.mdcontains provenance, decisions, coverage, gaps, and changelog.SPEC.mdcontains this maintenance contract.scripts/andassets/are intentionally absent until repeatable validation or templates are needed.
Evaluation
- Lightweight validation: run the skill validator, inspect routing coverage, and search new files for excluded API guidance.
- Deeper evaluation: run holdout prompts when trigger behavior or reference coverage changes materially.
- Holdout examples: keep examples in
SOURCES.mdunless they become large enough forreferences/evidence/. - Acceptance gates: all supported harnesses have a direct reference, every reference is routed from
SKILL.md, and no runtime guidance points outside the harness-backed model.
Known Limitations
- The skill does not automate installation; it is installable as a self-contained directory.
- Provider-specific model credentials and environment setup remain application concerns.
- API details must be refreshed when package options, peer ranges, or reporter behavior change.
Maintenance Notes
- Update
SKILL.mdwhen trigger language, routing, or universal defaults change. - Update
SOURCES.mdwhen source evidence, decisions, coverage, or gaps change. - Update harness reference files when a harness package option, runtime contract, normalization rule, or replay behavior changes.
- Add
references/evidence/only when repeated positive or negative examples become useful for future revisions.
Related skills
FAQ
What does vitest-evals do?
vitest-evals skill documents Use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom Harness adapters, first-party ai-sdk or pi-ai harness integrations, judges, replay, reporter-facing normalized run data, or examples and docs for these APIs.
When should I use vitest-evals?
User asks about vitest-evals, use when authoring, reviewing, or debugging harness-backed vitest-evals suites, custom har.
Is this skill safe to install?
Review the Security Audits panel on this page before installing in production.