Eval options control what a run records, how it runs, and how you recover when it stops: run settings, concurrency, async code, pinned context, and resuming. Configure them once your eval works and you need runs you can compare, debug, and finish after a crash. For a first run, start with Run your first eval; the Eval options and errors lists every option.
Before you begin
Before you start, make sure you have:- Working eval: An
Evalcall that runs, as in Run your first eval. - Client: An
AtlanClientfor reading results back, set up as in the quickstart’s verify step.
1
Set run options
These are the options to decide on for every run:
- Name: Keep it the same across branches and runs. Auto-registered scorers are named after it, and the CI action finds baselines by it.
config: Everything that distinguishes this run: model, prompt revision, commit, temperature. It is stored on the experiment, and you can filter on it withGET /eval/v1/experiments?config=model:example-model. Keep secrets out of it.- Concurrency: Python runs
max_concurrencycases at a time, which speeds up onlyasynctasks. TypeScript runs cases one at a time.
2
Verify run evidence
Read the run back before you trust a mean. A failure is handled like this:Results list 50 per page by default and at most 500; page with Before uploading a result,
A run where no scorer produces a usable value finalizes as
completed, then raises with the experiment ID. This includes runs where every task errored. Pass require_scores=False (requireScores: false) only when an empty score set is an expected outcome. Read the stored experiment’s summary.metrics.failed_cases (failedCases in TypeScript) and each result’s error to find the cause. The CI action treats an error rate above 20% as a broken run. In TypeScript, summary.scores is typed unknown; cast it before reading, for example run.summary.scores as Record<string, { mean: number; count: number }>.offset. input and output are stored as objects, so a string or number your task returned reads back as {"value": x}. The span read returns core,io fields by default; add attributes, usage, cost, or error to fields for more.To check a finished run’s evidence, for example after a crash or in a CI job that did not run Eval itself, call verify_experiment (verifyExperiment). It confirms the experiment is terminal and every result has a distinct, queryable trace, and checks a sample of traces for their score spans and span nesting. A content-policy check is reported as MANUAL: review it yourself.Eval waits up to 30 seconds for each case trace to be queryable, so no result points to a missing trace. The wait covers a trace that is not there yet and a trace plane that is down or slow: a trace read that fails with traces_unavailable (503) or request_timeout (504) is retried inside the window, respecting the server’s Retry-After when one is sent, until the window is spent and its error fails the run. Any other trace-read error fails the run immediately. If your trace export is slow, raise the wait with trace_verification_timeout_s (traceVerificationTimeoutMs). Turn verification off only for tests against a stub.3
Pin context that changed (optional)
config records settings. A context manifest records the version and SHA-256 digest of each input you identify, such as instructions, prompts, skills, tool schemas, or a retrieval snapshot. The SDK writes the manifest, and one digest over it, into the experiment config. Two runs with the same digest recorded the same manifest. Your runner must load and use the content it records; the digest alone does not verify that execution used it.The manifest is stored, but the referenced content is not fetched or checked, so point each entry at something you can still retrieve. Then compare runs by what you held constant:
4
Use async_eval in event loops (optional)
Python The task and scorers can be sync or async in both SDKs.
Eval starts its own event loop, so it fails inside an existing one, such as Jupyter, FastAPI, or an async test, with Eval() cannot run inside an event loop. Await async_eval there instead; it takes the same arguments.5
Pass case details to task (optional)
A task that declares a second parameter receives hooks: the case’s
expected, metadata, and tags, and the span the task runs in. Use the span to attach details to the trace.6
Resume stopped run (optional)
Save the experiment ID as soon as the run starts, then resume with the same arguments. Resume requires the experiment to still be
Eval skips the case IDs already stored and finishes the rest.running, in the same workspace, with the same dataset or inline cases, and the same config and context manifest. case_id on a record-backed run is the dataset record’s ID. Run one writer per experiment.To close a run you will not resume, mark it failed with the ID from the error message. An experiment left running stays in the list and never becomes a baseline. A failed experiment is frozen like a completed one.client.experiments.list(experiment_status="running") lists the open runs. Close only runs you own: another job’s run may still be in progress.Troubleshooting
Run failures include anEval call inside an event loop, a run left running after a trace timed out or a trace read failed, and a 409 on a duplicate experiment name. See Eval errors.
Next steps
- Gate pull requests with evals: Run the eval on every pull request and compare it with the default branch.
See also
- Eval options and errors: Every
Evaloption and its default. - Compare two agent versions: Diff two runs case by case.
- Record runs from your own harness: Record runs without
Eval.