Skip to main content
You can’t improve what you don’t measure, and you can’t measure agents without a runner. The Engine doesn’t ship its own eval harness — most teams write a small one. This page covers what a useful harness looks like.

What a harness does

A working harness in Python is ~150 lines.

Skeleton

That’s the whole runner. Add LLM-as-judge scoring as a separate function that gets called after the deterministic checks.

Loading cases

Cases live in JSON files (one per case) or a single JSONL file. Both work. JSON files are easier to diff in PRs; JSONL is easier to manage at scale.

Reporting

Pretty output is what makes evals usable:
Track previous runs to compare. Even a flat pass rate hides drifts in cost and latency.

Test isolation

Use a fresh task_id per case (suffix with the run ID and case ID). Otherwise memory bleeds between cases. For really clean isolation, run against a fresh Engine instance with an empty brain. A make eval-clean that wipes the brain volume and brings up the Engine gives you reproducible runs.

Concurrency

Run cases in parallel up to a budget. Provider rate limits set the ceiling; usually 5–10 concurrent works. Higher and you’ll start hitting LLM_RATE_LIMITED.

Storing results

Treat eval runs as data:
Compare across runs to detect drift. A run that passed 95% last week and 90% this week is news, even if the absolute number is fine.

CI integration

Quick suite (~20 cases) on every PR; full suite (~100 cases) on schedule (nightly) and before any release.
Fail the PR if the pass rate drops below the previous run.

See also