A verifier is the strongest evidence the harness can use. Where a judged metric estimates whether the agent did well, a verifier knows. It is optional, and worth wiring whenever it is possible at all.
The contract
- Signature:
(session_id, end_state) -> float | bool | None. Theend_stateis whatever your loop passed in the turn payload, so put the task identity in there. - May be sync or async — the harness adapts either.
- Returns: a float in
[0, 1](higher is better), a bool, orNone. Noneis a normal answer, not an error: a grader that can only score a finished task returnsNoneon every intermediate turn. The harness treats it as “no usable verdict” and carries on.- A broken verifier cannot break your loop. Exceptions are caught and logged; the turn proceeds without an outcome score. Values are clamped into range.
What it produces
A verdict becomes a syntheticoutcome_correct metric on the turn’s report, at tier 0 — which means it breaches on its absolute value (outcome_threshold, default 0.9), unlike the Tier-1 trajectory metrics.
It runs in parallel with the tier ladder rather than after it, because it depends only on the turn payload. On the barrier path that matters: its latency would otherwise stack on top of the evaluation’s.
Why it changes promotion
When a candidate rule is validated by replay, the harness has to pick which metric’s delta decides the verdict. It chooses the most authoritative metric that the replay actually produced, in trust order:outcome_correct— your verifier’s verdict on the replayed run.- The rule’s own declared
metric. - The metric named in the triggering signature.
A wired verifier that has no verdict for a particular case does not veto promotion. The target is chosen per case from the deltas that actually arrived — so a grader that can only score some tasks helps on those and stays out of the way on the rest. Treating an absent verdict as a failed target would veto promotion for every ungradeable case, which is why the fallback is per case rather than global.
Prefer a continuous score
Passing the task identity through
The verifier only sees what your loop puts inend_state, so include whatever your grader keys on:
end_state is what a captured eval case stores as its replay input, so one payload serves both the verifier and replay.
The facade’s bare
harness.turn(session_id) scope sends an empty end_state. If you want a verifier, call on_turn_end with a payload — or have your framework adapter supply one.Limits
- It does not replace the tiers.
outcome_correcttells you whether the turn succeeded; Tier 2 tells you which step went wrong, which is what a useful rule is written about. Both feed the same report. - It is not a gate on your agent. Like everything else on the producing side, it is observational: it shapes notices and promotion decisions, never the agent’s control flow.

