Skip to main content
Judge assertions are the fifth assertion mechanism, alongside the four covered in Assert. Use them when correctness cannot be expressed as a rule — for open-ended prose, tone, factual consistency, or summarization quality. The Judge model is entirely separate from the agent under test, which prevents self-evaluation bias: the same model grading its own output would be prone to rating itself generously.

The three judge shapes

t.judge.autoevals exposes exactly three fixed forms, whatever you’re evaluating maps onto one of them:
  • closedQA(question, opts?) — a closed-ended judgment: does the output satisfy this criterion? Best for rubric-style checks (“is the tone polite and specific”, “does this avoid inventing policy details”).
  • factuality(reference, opts?) — factual consistency between the output and a reference text you provide.
  • summarizes(source, opts?) — whether the output is a faithful summary of a source document.
Judge material is either bound by the receiver or passed explicitly: turn.judge defaults to that turn’s material, while root-level t.judge must receive explicit { input, output } strings (see below).

Where judge lives: t and turn

Like scoped assertions, judge calls follow the rule that the receiver decides the default material, not the call site:
turn.judge is turn-level: it only sees the message from that one turn, which is what you want when different turns in a multi-turn eval need different rubrics. Root-level t.judge carries no implicit material, so pass { input, output } explicitly for cross-turn, file, or other custom material:
To judge material that isn’t the conversation itself — a file’s current content or anything else — read it through the public Sandbox API and pass both strings explicitly:
Judge material is content you read; agent attribution is a separate claim made by fileChanged, not by what you pass to the Judge.

Judge model resolution

The judge model is resolved from most- to least-specific:
If neither level is set, the judge call fails at the call site as a configuration error. There is no built-in default judge model, and no environment variable for it — the model is configuration, so it comes from code only.

Judge endpoint and key: OpenAI-compatible protocol

Judge calls use an OpenAI-compatible /chat/completions protocol. OpenAI, DeepSeek, and any gateway compatible with that protocol can serve as the judge endpoint. Point at it in the judge config:
The endpoint is configuration and the key is a credential, so they come from different places: Point judge.baseUrl explicitly at your gateway or OpenAI-compatible proxy — NiceEval does not go looking for an endpoint in variables like OPENAI_BASE_URL. The key works the same way: exactly one name, either the one judge.apiKeyEnv names or the default NICEEVAL_JUDGE_KEY. The judge has its own credential and never borrows the one belonging to the app under test or to an agent.
When the model or key does not resolve, the judge assertion is recorded as unavailable (with a reason) rather than vanishing: unless you explicitly chain .optional(), an assertion that cannot be evaluated makes the attempt errored — a verdict nobody could reach is neither a pass nor the agent’s fault. After configuring keys, run one eval with t.judge and confirm the judge score appears in niceeval view.

Severity: judge defaults to soft

Judge calls are assertions, so they follow the same mechanics described in Assert · Gate vs soft severity — but their default is different from most value matchers:
With no .atLeast() and no .gate(), a bare judge call is recorded purely as a quality score — it shows up on the eval’s score chip but can never fail the run on its own. This is the right default for judge: it’s a probabilistic model assessing another probabilistic model’s output, and treating every rubric miss as a hard failure would make suites brittle and constantly red. Reach for .gate() only when the judged property is truly load-bearing (for example, “the response must not fabricate account details”).
  • Assert — gate vs soft severity in full, plus the verdict rules judge scores feed into.
  • Drivet.send(), t.newSession(), and which handle t.judge and turn.judge each hang off of.
  • Evals — how judge scores fold into the eval lifecycle and verdict types.