Eval Datasets
Everything a live evaluation runs on lives in one directory: evals/ inside
your skill. This page is the contract for that directory — what goes in it,
the dataset format tier3 evaluate reads, and how to generate and refine
cases.
You can generate a starter dataset with no API key; LLM-backed generation and
refinement need a configured provider (see
Providers & Credentials).
Tier 3 executes these cases through
Harbor, the open-source agent
evaluation framework. Native Harbor task bundles are the bring-your-own-task
alternative to the evals.json dataset described below.
The evals/ directory
SkillEvaluator recognizes this tree inside your skill:
Only the dataset is required. Everything else is optional and additive:
Unrecognized files in evals/ are ignored, and the validator warns about them
so typos don’t silently drop a fixture.
Dataset format
New datasets use the agentskills.io shape: a
top-level object with skill_name and an evals array.
The dataset file can be named evals.json, evals.jsonl, evals.yaml, or
evals.yml — tier3 evaluate accepts all four.
Legacy flat format
Older datasets are a flat array of entries with question instead of
prompt. They still run, but the validator emits a deprecation warning —
migrate to the agentskills.io shape for new work.
Generate a dataset
create-eval-dataset writes evals/evals.json for you, grounded in your
SKILL.md name, description, body, and script filenames:
Without an LLM provider configured, generation automatically falls back to the
same templates --no-llm uses, so the command always succeeds. Exact defaults
for every flag are in the
CLI Reference.
You don’t have to generate a dataset up front at all: tier3 evaluate --autopilot (and validate --full or validate --autopilot) creates exactly
one eval case when no evaluation source exists — LLM-generated with your
configured provider, falling back to a deterministic template case when no
key is available. Autopilot never overwrites an existing source; if
evals/evals.json (or evals/harbor/) is already there, it runs with what
you wrote.
--force overwrites evals/evals.json without a backup. --refine implies
overwrite too — it produces the final version of the dataset.
The four case buckets
--full generates one case per bucket. The mix matters: the negative case
protects against a skill that triggers when it shouldn’t.
Guide generation with EVAL.md
Place an EVAL.md in evals/ and the generator picks it up automatically.
Three headings are parsed as structured hints; everything else is general
context:
Author guidance is the highest-priority input: behaviors you list here are preserved in the generated cases even when a trial agent skipped them — that is exactly the regression the eval should catch.
Refine from real runs
--refine grounds the dataset in real agent behavior. It looks for existing
trajectories from a previous evaluation (checking --from-results or the
latest resolved results first); if none exist, it runs the claude-code agent
via Harbor to collect one, then rewrites expected_output and assertions from
what the agent actually did:
Collecting a fresh trajectory needs Docker, the tier3 extra, and a configured
provider. With --no-llm, refinement still works — it applies template-based
updates from the trajectory instead of an LLM rewrite.
Run policy: evals/config.yml
The dataset says what to evaluate; evals/config.yml (or config.yaml)
says how to run it. CLI flags always override config values.
Unknown keys are rejected, not ignored — a typo like n_attemps fails the
config load instead of silently running with defaults. Use only one of each
alias pair. Agent and provider credentials never go through runtime_env —
they come only from your host environment; see the two-credential-roles
section in Providers & Credentials.
Fixtures and custom environments
Two optional directories shape the world the agent works in.
evals/files/ holds input fixtures — test data, configs, sample
documents. The entire directory is copied into /workspace/input/ inside the
container, so prompts can reference those paths directly.
evals/environment/ customizes the container itself:
Validate before you run
Check the whole contract — dataset fields, case IDs, config.yml, Dockerfile
rules, MCP declarations — without launching anything:
Run it in CI or before a long evaluation: it catches an empty dataset, missing required fields, duplicate case IDs, and invalid config in seconds.