skillevaluation is an open format and a reference runner for benchmarking an agent skill. You write test cases in eval.yaml, next to SKILL.md, and they answer one question:
Does this skill actually help an agent? By how much?Each case runs twice, with the skill and without it. The difference is the skill’s lift (how much better the agent does with the skill than without). The format and runner don’t need DecimalAI.
pip install "skillevaluation[runner]" runs a full benchmark on your machine, on your own API key, with no account. DecimalAI’s hosted runner imports the same judge and scoring code, and adds history, verified results and rankings. The package is Apache 2.0.
Keeping the suite beside the skill means you version the cases with the skill, and decimalai skills pull brings them along.
The 60-second format
cases is the only top-level key. Unknown keys are rejected at every level, so a typo such as expectation: fails loudly instead of being dropped.
Every case needs
expectations or validators, or a should_trigger flag. Use a validator when a program can check the answer, and an expectation for a claim about meaning.
Validators and setup commands run in the case’s workspace. A validator finds the agent’s final output in ./response.txt and $RESPONSE_TEXT. It passes when its exit code equals expect_exit_code. A timeout, a command that can’t start, or an exit code that is neither 0, 1 nor the declared one gives no verdict, and the case drops out of the lift rather than counting as a model failure.
The old keys mode, user_goal, environment, simulator, policy_check and trials are rejected, with a message saying what to do instead.
What a run reports
Each case lands in one of five outcomes:
The total is the skill’s lift, reported as something like “+34 pts pass rate, −46% agent turns” (illustrative).
A run that mostly errored has no headline. When more than 25% of a run’s cases error, such as during a provider outage, the result is stamped
error_dominated: true and the pass-rate difference is left empty. Re-run it. The hosted runner applies the same floor.
Trigger cases: should_trigger
Graded cases prove a skill helps when it’s loaded. Trigger cases prove it loads at the right times.
should_trigger and no grader is trigger-only. A case can also carry both, and then it’s graded for lift too.
The local runner doesn’t score trigger accuracy. It keeps trigger-only cases out of the lift and reports how many in cases_skipped_trigger_only.
A hosted run does score them: it builds a skill list with your skill among others, asks the model which it would use, and reports menu_selection_rate and false_fire_rate, plus router_recall for retrieval against the live skill index. When these fail, fix the description, not the body.
Run it locally (free)
Your API key, your machine, and nothing is sent to DecimalAI:results.json. Local runs are unlimited.
The default adapter makes one completion per run with the
SKILL.md body in the prompt, so bundled references/ aren’t read.
--runs: average out the luck
Model behavior is probabilistic, and one run per case measures luck. skillevaluation run ./my-skill --runs 3 repeats the whole suite three times and averages by mean, up to 10 runs. The expected pass rate doesn’t change with the count: more runs only narrow the error bars. Repetition is a runner flag, so no case can weigh more than another.
results.json holds one record per case, with rates averaged over every run. To inspect flakiness run by run, execute the suite once per run.
Push results to DecimalAI
Attach a local run to your skill’s Benchmark tab. It’s free and uses no quota. It needs thedecimalai package and an API key, and you sync first, so the platform knows the skill and its cases:
Verified runs (hosted)
A verified run is one DecimalAI’s runner executed, stamped with the model and date. Only verified runs feed registry cards, rankings and SkillScore.
Two more rules apply to the verified number:
- An expectation has to earn its place. It counts only when the with-skill side passes it more often than the without-skill side. One that doesn’t separate them is shown but not counted. If none count, the run has no lift.
- A public lift needs at least 8 cases that count. Below that, the run is recorded and no lift appears on the skill’s public page.
Bring your own runner
The runner contract (spec/runner-contract.md), CONFORMANCE.md and the golden compatibility-tests/ fixtures ship inside the package. Any implementation that reproduces the fixtures conforms. The JSON Schemas load by short name:
Composing with agentversion
A manifest can record a run’s score underevaluation.gates[], so a lifecycle change can cite a suite’s verdict as evidence:
name, actual_score, threshold, passed and ran_at are required. evaluator_ref is optional and names the suite: its content hash and the spec version it was written against.
Status
The package is at 0.8.0 on PyPI, in beta, and breaking changes are possible before 1.0. Theeval.yaml shape on this page is schema rev 2. See the package changelog for each release.