Skip to main content
Your workflows have evaluator steps that power generate-evaluate-retry loops in production. Evaluation workflows answer a different question: “across a set of known inputs, does my workflow still produce acceptable output?” Workflow evaluators run outside your workflow. You define evaluators with verify(), write test cases as YAML datasets, and run them with the CLI. The framework feeds each dataset case through your evaluators and reports pass/partial/fail verdicts. Nothing in your production workflow changes. This is how you catch regressions when you update a prompt, swap a model, or refactor a step. Run evals before deploying and you’ll know if quality dropped.

Evaluator Step vs Evaluation Workflow

These serve different purposes and live in different places: Evaluator steps are documented in Evaluator Step. This section covers evaluation workflows.

Directory Structure

Eval files live alongside your workflow in a tests/ directory:
The eval workflow file (tests/evals/workflow.ts) is discovered automatically by the worker alongside your regular workflow.

Nested workflow folders

Workflow folders nest to any depth. A workflow at src/workflows/content/writing/style_anchor/ registered as content_writing_style_anchor keeps its evals and datasets in its own tests/ directory, and the CLI resolves them by the registered name — no symlink and no flat folder required.
The eval workflow only registers if tests/evals/workflow.ts compiles to dist — the worker loads workflows from the compiled output, not from source. A tsconfig that excludes the whole src/**/tests tree silently drops it, and output workflow test then can’t find <workflow>_eval. Exclude test files individually instead:
tsconfig.json
When the eval source exists but isn’t registered, output workflow test says so and points at this fix instead of failing with a generic “workflow not found”.

Writing Evaluators with verify()

verify() creates a typed evaluator that receives the workflow’s input, output, and optional ground truth from the dataset. It wraps evaluator() from @outputai/core, so it integrates with both the eval workflow and the Temporal worker.
tests/evals/evaluators.ts
The check function receives a CheckContext with three fields: The input and output schemas are optional — they default to z.any() if omitted. When provided, they give you type safety inside the check function.

Using Ground Truth

Evaluators can read expected values from the dataset’s ground_truth field. This lets you define per-case expectations without hardcoding them:
tests/evals/evaluators.ts
The min_length value comes from the dataset YAML — see Ground Truth Structure for how this works.

Verdict Helpers

The Verdict object provides helpers for returning evaluation results. There are three categories:
  • Deterministic assertionsequals, gte, contains, matches, etc. Return EvaluationBooleanResult with confidence: 1.0.
  • Manual verdictspass(), partial(), fail(). Return EvaluationVerdictResult for custom logic.
  • LLM result wrappersfromJudge(), score(), label(). Wrap LLM output with confidence: 0.9.
tests/evals/evaluators.ts
For the complete reference with signatures, examples, and edge cases for every Verdict method, see Verdict Helpers.

LLM Judge Functions

For subjective evaluation — “is this blog post on-topic?”, “rate the quality” — use the judge functions. They load a .prompt file, call the LLM, and return a typed evaluation result. Four judge functions are available:
tests/evals/evaluators.ts
All judge functions accept a JudgeArgs object:

Writing Judge Prompts

Judge .prompt files live in the same tests/evals/ directory as your evaluators. Each judge function expects a specific output schema from the LLM: Here’s a judge prompt for topic evaluation:
tests/evals/judge_topic@v1.prompt
Use temperature: 0 for judge prompts — you want consistency, not creativity. For best practices on writing effective judge prompts, see LLM-as-a-Judge Best Practices.

LLM Result Wrappers

If you’re calling the LLM yourself instead of using the judge functions, the Verdict object provides wrappers to convert raw LLM output into evaluation results (with confidence 0.9). See LLM Result Wrappers for the full reference.

What’s Next