cd /news/ai-tools/show-hn-understudy-scenario-testing-… · home topics ai-tools article
[ARTICLE · art-113765] src=github.com ↗ pub= topic=ai-tools verified=true sentiment=· neutral

Show HN: Understudy: Scenario Testing for AI Agents

Goji Plus released Understudy, an open-source scenario-driven testing framework for AI agents that simulates multi-turn users, records execution traces, and asserts on tool calls rather than prose. The framework supports ADK, LangGraph, and HTTP agents, offers mock toolkits, YAML scene definitions, and pytest integration, and is installable via `pip install understudy[all]`.

read4 min views3 publishedAug 28, 2026
Show HN: Understudy: Scenario Testing for AI Agents
Image: Michielbdejong (auto-discovered)

Understudy is a scenario-driven testing framework for AI agents that simulates realistic multi-turn users, runs those scenes against an agent through a simple app adapter, records a structured execution trace of messages, tool calls, and handoffs, and then evaluates behavior with deterministic checks, optional LLM judges, and run reports.

Testing with understudy is 4 steps:

Wrap your agent— Adapt your agent (ADK, LangGraph, HTTP) to understudy's interface** Mock your tools**— Register handlers that return test data instead of calling real services** Write scenes**— YAML files defining what the simulated user wants and what you expect** Run and assert**— Execute simulations, check traces, generate reports

The key insight: assert against the trace, not the prose. Don't check what the agent said—check what it did (tool calls).

Simulate multi-turn conversations with personas to test dialogue agents.

  • Use case: Customer service bots, assistants, chatbots
  • Assert on tool calls: trace.called("tool_name")

Evaluate autonomous agents executing multi-step tasks.

  • Use case: Code agents, research agents, task automation
  • Assert on actions: trace.performed("action")

See examples/README.md for complete examples of both paradigms.

See real examples:

Example scene— YAML defining a test scenarioADK test file— pytest assertions against tracesLangGraph test file— same tests, different frameworkAgentic test file— agentic flow evaluationAgentic scene— task-based scenarioExample report— HTML report with metrics and transcripts

pip install understudy[all]
python
from understudy.adk import ADKApp
from my_agent import agent

app = ADKApp(agent=agent)

Your agent has tools that call external services. Mock them for testing:

from understudy.mocks import MockToolkit

mocks = MockToolkit()

@mocks.handle("lookup_order")
def lookup_order(order_id: str) -> dict:
    return {"order_id": order_id, "items": [...], "status": "delivered"}

@mocks.handle("create_return")
def create_return(order_id: str, item_sku: str, reason: str) -> dict:
    return {"return_id": "RET-001", "status": "created"}

Create scenes/return_backpack.yaml

:

id: return_eligible_backpack
description: Customer wants to return a backpack

starting_prompt: "I'd like to return an item please."
conversation_plan: |
  Goal: Return the hiking backpack from order ORD-10031.
  - Provide order ID when asked
  - Return reason: too small

persona: cooperative
max_turns: 15

expectations:
  required_tools:
    - lookup_order
    - create_return
  forbidden_tools:
    - issue_refund
python
from understudy import Scene, run

scene = Scene.from_file("scenes/return_backpack.yaml")
trace = run(app, scene, mocks=mocks)

assert trace.called("lookup_order")
assert trace.called("create_return")
assert not trace.called("issue_refund")

Or with pytest (define app

and mocks

fixtures in conftest.py):

pytest test_returns.py -v

Run multiple scenes with multiple simulations per scene:

from understudy import Suite, RunStorage

suite = Suite.from_directory("scenes/")
storage = RunStorage()

results = suite.run(
    app,
    mocks=mocks,
    storage=storage,
    n_sims=3,
    tags={"version": "v1"},
)
print(f"{results.pass_count}/{len(results.results)} passed")

Understudy separates simulation (generating traces) from evaluation (checking traces). Use together or separately:

understudy run \
  --app mymodule:agent_app \
  --scene ./scenes/ \
  --n-sims 3 \
  --junit results.xml

Generate traces only:

understudy simulate \
  --app mymodule:agent_app \
  --scenes ./scenes/ \
  --output ./traces/ \
  --n-sims 3

Evaluate existing traces:

understudy evaluate \
  --traces ./traces/ \
  --output ./results/ \
  --junit results.xml

Python API:

from understudy import simulate_batch, evaluate_batch

traces = simulate_batch(
    app=agent_app,
    scenes="./scenes/",
    n_sims=3,
    output="./traces/",
)

results = evaluate_batch(
    traces="./traces/",
    output="./results/",
)
understudy run --app mymodule:app --scene ./scenes/
understudy simulate --app mymodule:app --scenes ./scenes/
understudy evaluate --traces ./traces/

understudy list
understudy show <run_id>
understudy summary

understudy compare --tag version --before v1 --after v2

understudy report -o report.html
understudy compare --tag version --before v1 --after v2 --html comparison.html

understudy serve --port 8080

understudy serve-api --port 8000

understudy delete <run_id>
understudy clear

For qualities that can't be checked deterministically:

from understudy.judges import Judge

empathy_judge = Judge(
    rubric="The agent acknowledged frustration and was empathetic while enforcing policy.",
    samples=5,
)

result = empathy_judge.evaluate(trace)
assert result.score == 1

Built-in rubrics:

from understudy.judges import (
    TOOL_USAGE_CORRECTNESS,
    POLICY_COMPLIANCE,
    TONE_EMPATHY,
    ADVERSARIAL_ROBUSTNESS,
    TASK_COMPLETION,
)

The understudy summary

command shows:

Pass rate— percentage of scenes that passed all expectations** Avg turns**— average conversation length** Tool usage**— distribution of tool calls across runs** Agents**— which agents were invoked

The HTML report (understudy report

) includes:

  • All metrics above
  • Full conversation transcripts
  • Tool call details with arguments
  • Expectation check results
  • Judge evaluation results (when used)

See the full documentation for:

Installation guideWriting scenesADK integrationLangGraph integrationHTTP client for deployed agentsAPI reference

MIT

── more in #ai-tools 4 stories · sorted by recency
── more on @goji plus 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-understudy-s…] indexed:0 read:4min 2026-08-28 ·