The two shapes
Pest-shaped — evals live in your test suite, CI adds the flag:.github/workflows/evals.yml
The eval step
--baseline is doing real work here. Unlike the Pest surface, the CLI never promotes a
baseline on its own — without it there is nothing for --compare=baseline to resolve, and
every run reports “No reference run found for —compare=baseline” forever. With it, each
gate-passing run becomes the reference for the next.0 clean, 1 regression/gate failure, 2 harness failure. See CLI.
Baselines in CI
Baselines are established differently on each surface — in Pest the first gate-passing run auto-baselines its suite; from the CLI you ask for it with--baseline. Either way, the CI question is where the baseline lives: comparison needs a database with history. Two workable setups:
- Shared eval database (recommended): point CI’s
DB_*at a small persistent database (the same one your dashboard reads). Every CI run lands in history, baselines persist, and the dashboard shows your CI runs’ trends for free. - Ephemeral DB, artifact-driven: run with a throwaway database and treat the JSON report as the record. You lose
--compare(no history to compare against) but keep absolute gates (--min-score,--min-pass-rate).
Controlling cost
samples(2–3)is usually enough signal for CI; savesamples(10)for investigations.- Gates skip judges on broken samples automatically — your worst PRs are your cheapest.
- Set
min:thresholds only on calibrated judges; a miscalibrated judge burns tokens and trust. - The JSON report includes total and judge cost per run — chart it; eval spend that drifts up usually means a dataset quietly grew.
Keys and safety rails
Provider keys come from CI secrets, judge configuration viaEVALS_JUDGE_PROVIDER / EVALS_JUDGE_MODEL. And keep a wiring check in the normal test lane so breakage surfaces before the expensive lane runs:
Cheap lane (every push)