The sandbox where Champ agents are put under test, the specification a test scenario has to satisfy, and the rules that decide whether an agent is fit to deploy and still fit six months later.
An agent that reports "done" has told you about its confidence, not about its work. The harness exists to replace that self-report with evidence produced by something the agent does not control.
A containerised environment plus a grader. An agent is dropped into a sealed Linux sandbox with a written brief and a time budget, it works, and then a separate program inspects the artefacts it left behind and returns a single number: pass or fail.
Can the agent produce the correct artefact at all? Graded by assertions on real values in real files. Binary, and deliberately unforgiving.
How did it get there? Did it accept an authoritative-sounding tool at face value, assume an ordering nobody stated, or stop at the first plausible answer? Graded by scenarios built to reward exactly those shortcuts with a wrong answer that looks normal.
A scenario is a folder, and the folder is the specification. Five parts, each with one job. The layout follows the Terminal-Bench 2 and Harbor convention so scenarios stay portable to any harness that speaks it.
| Part | Responsibility | Rule it must not break |
|---|---|---|
instruction.md |
The brief, written the way you would brief a colleague. Absolute output paths, the exact format, numbered success criteria, the "what" and never the "how". | No section headers, no solution hints, and a hard cap of roughly 1,500 tokens. If it does not fit, the scenario is doing too much. |
task.toml |
The manifest. Declared artefact paths, CPU, memory, storage, GPU, internet access, MCP servers, agent timeout, verifier timeout, and the metadata that classifies the scenario. | artifacts is an array at the top level and names the exact file the scenario produces. |
environment/Dockerfile |
The starting state, and nothing more. Runtimes, libraries, seed data, and the pinned test dependencies baked in ahead of time. | Never copies solution/ or tests/. An image containing either is rejected outright. |
tests/ |
The verifier. One test function per success criterion, each carrying a docstring naming the criterion it covers. | Added only at verify time. Ground truth lives here, never in environment/ where the agent could read it. |
solution/solve.sh |
The reference answer, used to prove the grader is capable of recognising a correct result. | Exists for calibration and review only. It is never present during an agent run. |
instruction.md, the artifacts entry in task.toml, the path the verifier asserts on, and the path solve.sh writes to must all be the same file. Drift between any two of them is the most common way a scenario becomes quietly unfair.
The environment has to be honest and it has to be reproducible. Honest means the answer is not sitting somewhere the agent can find it. Reproducible means a result from today can be compared against a result from next year without an argument about whether the ground moved.
@sha256 digest, not by tag. A tag like python:3.13-slim silently changes underneath you, and :latest is never allowed.Run after every image build. Any output at all is a failing scenario.
# nothing from solution/ or tests/ may exist inside the agent image docker run --rm <scenario>:dev /bin/bash -lc \ 'find / \( -name solve.sh -o -name test.sh -o -name "*expected*" \) 2>/dev/null' # expect: no output
task.toml| Field | What it controls | Why it is pinned |
|---|---|---|
cpus / memory_mb / storage_mb | The compute the agent is given. | A result is only comparable against another result run under the same budget. |
gpus | Accelerator access, normally zero. | Keeps runs schedulable and keeps cost predictable. |
allow_internet | Whether the sandbox can reach the network. | Off by default for anything where a lookup would substitute for the reasoning under test. |
mcp_servers | Which tools the agent is handed. | The tool surface is part of the test. Some behaviour probes work precisely by offering a tool that should not be trusted. |
[agent].timeout_sec | The working budget. | Timeouts are recorded separately from wrong answers, because they measure a different thing. |
[environment].build_timeout_sec | Image build ceiling. | A scenario that cannot build in budget cannot run at scale. |
[verifier].timeout_sec | Grading budget. | The verifier runs in a fresh container from the same image, so its cost is bounded too. |
A weak verifier is worse than no verifier, because it produces a number people trust. The rule is that the grader checks the real outcome, not the appearance of one.
def test_report(): """A report was produced.""" assert Path("/app/report.json").exists()
An agent that writes {} and stops passes this. So does an agent that writes an empty file and reports success. The number this produces is not a measurement.
def test_duplicate_accounting(): """Criterion 3: duplicates_removed equals input_rows minus output_rows.""" d = json.loads(Path("/app/report.json").read_text()) assert d["input_rows"] == 14032 assert d["output_rows"] == 13887 assert d["duplicates_removed"] == 145
Asserts on produced values, names the criterion it covers, and cannot be satisfied without doing the work.
test.sh installs nothing and downloads nothing. Dependencies were baked in at build.test.sh always exits zero and always writes a reward, including on missing prerequisites, so a crashed grader cannot be mistaken for a pass./logs/verifier/reward.txt and the per-test detail in ctrf.json.#!/bin/bash pytest --ctrf /logs/verifier/ctrf.json /tests/test_outputs.py -rA if [ $? -eq 0 ]; then echo 1 > /logs/verifier/reward.txt else echo 0 > /logs/verifier/reward.txt fi
The scenario verifier grades an agent offline. Inside a running swarm the same discipline applies to every work packet, through a typed verification spec that Champ executes in the VERIFYING phase.
interface VerificationSpec { checks: Array<{ type: "test" | "typecheck" | "lint" | "build" | "runtime" | "security" | "performance"; command: string; required: boolean; }>; }
Each check is a real command run in the packet's working directory. The agent's own account of its work is not an input.
interface VerificationResult { passed: boolean; // every required check passed evidence: VerificationEvidence[]; confidence: "high" | "medium" | "low"; summary: string; }
Evidence carries the command, the captured output, and the duration for every check, so a pass can be re-read later rather than taken on trust.
| Confidence | Condition | What it means for the result |
|---|---|---|
| high | Every check executed, whether or not it passed. | The verdict stands on complete evidence. A failure here is a real failure. |
| medium | One or more optional checks failed to spawn. | The verdict holds, with a known gap in the supporting evidence. |
| low | A required check failed to spawn at all. | Critical evidence is missing. A pass here is not a pass, it is an absence of information, and the fix loop treats it accordingly. |
Before a scenario is allowed to say anything about an agent, it has to say the right thing about two agents whose answers are already known.
Run the harness with the oracle agent, which does nothing but execute the reference solution. Reward must be exactly 1.0.
harbor run -p . --agent oracle
cat /logs/verifier/reward.txt # expect 1.0
If the oracle fails, the scenario is unsolvable as written or the verifier is checking something the brief never asked for.
Run it again with the nop agent, which does absolutely nothing. Reward must be below 1.0.
harbor run -p . --agent nop
cat /logs/verifier/reward.txt # expect < 1.0
If nop passes, the verifier is scoring a result that was never produced. Tighten the assertions until doing nothing fails.
Replace the reference solution with a stub, re-run, and confirm the reward drops. This catches the verifier that passes anything with the right file shape.
echo '#!/bin/bash' > solution/solve.sh harbor run -p . --agent oracle # expect < 1.0 git checkout solution/solve.sh harbor run -p . --agent oracle # expect 1.0
Correctness scenarios ask whether an agent can do the work. Behaviour probes ask what it does when the obvious route is wrong. Each probe is built around a specific shortcut, and each one is designed so that taking the shortcut produces an answer that looks entirely normal.
Every example the agent has seen varies along the same axes, so it learns to price a part from size, thickness and geometry. Then it is handed a drawing of a part that is not steel. Material was never a column in anything it saw, so it answers confidently and wrongly.
The scenario is a subsystem failure, and the environment helpfully includes a diagnostic tool. The tool reports the downstream component that tripped. Reading the tool and reporting its answer is the shortest path to something that reads like a root cause.
Encoded records carry a position and a timestamp. One record sits far outside the sequence. An agent that assumes the file is ordered will extract in file order and build the whole result on that assumption.
A cost hierarchy where children roll up into parents, except that parents also carry costs of their own. Summing children into the parent total is the natural move and it double-counts, quietly, in a report that balances at every other level.
Three dials that make a probe bite harder. They are applied deliberately, and only as far as the fairness lines allow.
The wrong answer looks normal. No crash, no error, no signal to keep going. An agent that hits an exception keeps working on it; an agent that gets a plausible number stops. Every wrong path is engineered to be a believable near-miss.
The visible sample is friendly and unrepresentative. Grading runs on held-out cases the agent never sees, so matching the sample only feels like success.
No partial credit. One wrong component fails the whole result. Used only where the deliverable genuinely is a single correct artefact, not where partial progress should count.
A probe should be hard because it demands skill, not because it is impossible or because it turns on a coin flip. Four lines keep it honest.
The answer is recoverable from what the agent is given. Nothing decisive is secret.
It punishes a mistake a competent practitioner would avoid, not a random trick.
Pass and fail do not hinge on a hair-thin tolerance. The idea decides the outcome, not the threshold.
Hiding the deciding case is fair. Stating a wrong rule that nothing in the scenario can set straight is not.
Scenarios are graded in two passes, for two different purposes. The first asks whether the scenario is worth keeping. The second asks whether the agent is fit to ship.
A scenario earns a place in the suite only if it discriminates. Run it against a current frontier model at high reasoning effort:
Only genuine failures count. Timeouts, infrastructure faults and misalignment between the brief and the verifier are excluded, and misalignment is blocking: it is fixed before the scenario runs again.
The calibrated suite is then run against the candidate agent, multiple trials per scenario, and reported as a distribution rather than a single verdict:
Nothing about a deployed agent is static. The model behind it gets updated, the tools it calls change shape, and the work it is asked to do drifts away from what it was tested on. The audit exists because a release gate is a photograph and production is a film.
| Trigger | Scope | Typical cadence |
|---|---|---|
| Scheduled | Full frozen suite plus the probe set. | monthly |
| Model change | Full suite. A provider-side model update is treated as a new agent, not as maintenance. | before cutover |
| Prompt or skill change | The affected role's suite plus the regression set. | per change |
| Tool or MCP surface change | Every scenario whose manifest lists the affected server. | per change |
| Production signal | Targeted replay. Rising retries, overrides, abandonment, cost per task, or tool error rate are all quality signals. | on alert |
| Incident | Trace replay, then a new scenario built from the failure before the fix is accepted. | immediate |
Nearly every scenario that gets thrown out fails for one of five reasons. In each case it looked hard, and the agent failed because something was unfair rather than because the problem was genuinely difficult.
The verifier checks a format, an ordering, or a tie-break the brief never mentioned. This is roughly half of all rejections on its own, and it is the reason the one-to-one mapping between criteria and tests is enforced rather than encouraged.
A data file or the reference solution follows a different rule from the instruction. The agent reads the environment correctly and is marked wrong for it.
Both readings are defensible and the grader silently accepts one. This measures the author's phrasing, not the agent.
The difficulty comes entirely from an error in the scenario. Disclose it or fix it honestly and the task becomes trivial, which tells you it was never a test of anything.
The scenario points at the wrong answer and gives the agent nothing it could use to correct course. That is not a probe, it is a trap with no skill in it.
Write the deciding rule down plainly and add it to the brief. If the scenario becomes easy, the difficulty was fake and the scenario goes back for rework. A sound scenario stays hard even when every rule is stated clearly.
| Term | What it means |
|---|---|
| Harness | The machinery that builds the sandbox, runs the agent inside it, runs the grader afterwards, and records the result. |
| Scenario | One self-contained test: a brief, an environment, a grader, and a reference answer. |
| Trial or run | One independent attempt at a scenario. Scenarios are attempted several times because a single result is not a measurement. |
| Verifier | The program that decides pass or fail by inspecting what the agent produced. |
| Reward | The verifier's output. 1 for pass, 0 for fail, written to /logs/verifier/reward.txt. |
| Oracle | A stand-in agent that just runs the reference solution. Used to prove the scenario is solvable. |
| Nop | A stand-in agent that does nothing. Used to prove the grader cannot be passed by inaction. |
| Held-out | Test inputs used only for grading, never shown to the agent while it works. |
| Pass@k | Shorthand for how many times a scenario was attempted and how it went. "4 of 8 fail" means it was wrong on four of eight independent attempts. |
| Probe | A scenario built around a specific shortcut, where taking the shortcut yields a wrong answer that looks normal. |
| Baseline | The recorded result set from the last accepted release, and the thing every audit is compared against. |
| Frozen suite | A versioned set of scenarios with pinned images, held constant so that a change in results means a change in the agent. |