BehavTest

BehavTest › Reference

Suite format

A suite is a JSON file. Add "$schema" for editor autocomplete and validation (behavtest schema prints the schema).

{
  "$schema": "https://unpkg.com/behavtest/schema/suite.schema.json",
  "name": "support-bot",
  "description": "Regression suite for the support assistant",
  "defaults": { "judge": "anthropic:claude-sonnet-5", "repeat": 1, "timeoutMs": 30000, "concurrency": 4 },
  "pipeline": {
    "adapter": "http",
    "config": {
      "url": "${PIPELINE_URL:-http://localhost:4000/pipeline}",
      "headers": { "Authorization": "Bearer ${PIPELINE_TOKEN}" }
    }
  },
  "cases": [
    {
      "id": "refund-policy",
      "input": "Can I return an item after 40 days?",
      "expected": "No: returns are accepted within 30 days.",
      "tags": ["policy"],
      "scorers": ["llmJudge", "latencyCost"],
      "scorerConfig": {
        "llmJudge": { "rubric": "Does the answer state the 30-day limit and avoid promising an exception?" },
        "latencyCost": { "maxLatencyMs": 3000 }
      }
    },
    {
      "id": "order-status",
      "input": { "messages": [{ "role": "user", "content": "Where is order 123?" }] },
      "expected": "Your order shipped on Monday.",
      "scorers": ["exactMatch"],
      "repeat": 5
    }
  ]
}
FieldMeaning
cases[].idUnique and stable across runs: it is how future comparisons match cases. Letters, digits, ., _, -.
cases[].inputA string, { "messages": [...] } (chat history), or any object (sent as-is to HTTP pipelines; LLM adapters need inputTemplate).
cases[].expectedReference answer. Required by exactMatch; optional context for llmJudge.
cases[].expectedDocsIds of the documents a correct retrieval returns, for the retrieval scorer.
cases[].scorersNames of scorers to run. scorerConfig.<name> holds that scorer's options.
cases[].tagsLabels for filtering with --tag.
cases[].repeat / timeoutMsPer-case overrides. CLI flags beat case values, which beat defaults.
${VAR} / ${VAR:-default}Environment placeholders, allowed in any string of pipeline.config. Secrets belong here, never in the file. A missing variable stops the run before anything is sent.
pricingOptional extra/override model prices (see cost).
variantsOptional: run the suite once per variant (see matrix runs). Each is { name, description?, pipeline?: { adapter?, config? } }.

Unknown keys are rejected, so typos like scorer (instead of scorers) fail loudly, with the JSON path.