Skip to main content
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.
A case with 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:
You get a table of differences and a 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 the decimalai package and an API key, and you sync first, so the platform knows the skill and its cases:
Pushed runs are tagged unverified. They show on your skill’s own page and never feed registry rankings.

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.
Or click Run benchmark on the skill’s page. Publishing doesn’t run one for you. Hosted runs are metered in cases: one case is both runs plus the judge, errored cases are refunded, and a single run holds at most 200 cases. See Pricing → Quota enforcement. The hosted runner doesn’t run your code, and that decides how you grade: 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 under evaluation.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. The eval.yaml shape on this page is schema rev 2. See the package changelog for each release.