Skip to main content
eval runs the project’s saved test conversations against the agent and scores each reply. Every case runs in a fresh conversation, eval-<case>-<nonce>, so cases never share memory or history, and each turn goes through the same send-and-wait path as invoke. With arguments, each one is a case file (a path ending in .jsonl or .json) or a case name; with none, every file under evals/ runs. create writes evals/basic.jsonl with one case, so a new project has something to run:

Cases

Cases live in evals/: a .jsonl file holds one case per line (blank lines and lines starting with // are skipped), and a .json file holds an array of cases.
Parsing is strict: an unknown key, an empty value, or a regular expression that does not compile is an error that names the file and the line, evals/basic.jsonl:3: unknown check expect.contain, and nothing runs. A case with nothing to check is refused too.

Checks

Every check given in an expect must hold. The judge runs on Telnyx inference as the signed-in account, the same way dev runs the agent’s model, and answers pass or fail with one sentence of why. A model that needs its own provider key reads it from the environment or from the project’s .env. The conversation and the reply go to the judge as data it is told never to follow, so a reply cannot rewrite its own criterion.

Outcomes

A tool or noTool check is skipped, not failed, when the agent keeps no trace of the run, or was deployed before traces existed: tool web_search skipped: needs traces.
eval exits 0 whatever the cases’ outcomes unless --ci is given. It exits 2 on a usage error, before any case runs: a case file that does not parse, a missing evals/, an unknown case name, an unreadable --compare file. It exits 1 when the agent cannot be reached at all (not deployed, or no dev running under --local). Under --json the envelope’s data holds the agent, the target (dev or deployed), the judge model, a summary (total, passed, failed, errors, skipped, skippedChecks, p50Ms, p95Ms), and every case with each turn’s reply, run id, time and checks.

In CI

Deploy, then fail the job when any case fails:
A later run with --compare eval-results.json says what changed since: