Quick start
This page sets up a project, writes a suite for a REST agent and a voice agent, validates it and
checks the setup with tamesu doctor. You need a tamesu binary (see Install).
Scaffold a project
mkdir support-tests && cd support-tests
tamesu init
created tamesu.yaml
created examples/README.md
created examples/support-agent.yaml
Next: edit tamesu.yaml and examples/, then run `tamesu validate` and `tamesu doctor`.
tamesu.yaml holds the project defaults: which suites to use, the Genkit plugins and models,
timeouts, budgets, reporters and the project-wide secret refs. examples/support-agent.yaml is a
suite with two targets, a REST agent and a LiveKit voice agent, and one test for each.
Read the suite
suite: support-agent
tags: [smoke]
vars:
user: qa@example.com
secrets: # mamori refs, never values
API_TOKEN: env:SUPPORT_API_TOKEN
LIVEKIT_API_KEY: env:LIVEKIT_API_KEY
LIVEKIT_API_SECRET: env:LIVEKIT_API_SECRET
targets:
api:
type: rest
url: ${AGENT_URL:-http://localhost:8080/chat}
headers: { Authorization: "Bearer {{secrets.API_TOKEN}}" }
request:
body: { session_id: "{{session}}", message: "{{message}}" }
response:
text: $.reply
tool_calls: $.tool_calls[*].name
done: $.end_session
voice:
type: livekit
url: ${LIVEKIT_URL:-ws://localhost:7880}
api_key: "{{secrets.LIVEKIT_API_KEY}}"
api_secret: "{{secrets.LIVEKIT_API_SECRET}}"
room: "support-{{uuid}}"
mode: text
tests:
- name: refund policy question
target: api
persona: { name: Marta, style: "polite, slightly confused", language: en }
scenario:
goal: "Find out if you can return shoes bought 40 days ago"
max_turns: 8
stop_when: "the agent has given a clear yes/no answer"
assert:
- judge: "The agent states the return policy and does not promise an exception"
- not_contains: "I'm just an AI"
- metric: { name: turn_latency_p95_ms, lt: 4000 }
Three things to notice:
- Secrets are references.
env:SUPPORT_API_TOKENtells mamori where to find the token; the suite uses it as{{secrets.API_TOKEN}}. A chain such asenv:SUPPORT_API_TOKEN,aws-sm://ci/support#tokentries each link in order. ${VAR:-default}is for non-secret values. The agent URL falls back to localhost so the suite validates anywhere.tamesu validatewarns if you use${VAR}for a key.- Assertions mix kinds. A
judgerubric graded by a model, a deterministicnot_contains, and ametricon the p95 turn latency. See Concepts.
Validate
tamesu validate
1 suite, 2 tests, 0 errors, 0 warnings
Break something to see how errors look. Point the test at a target that does not exist:
sed -i 's/target: api/target: nope/' examples/support-agent.yaml
tamesu validate; echo "exit $?"
examples/support-agent.yaml:40: tests[0] "refund policy question".target: target "nope" is not declared in targets (have api, voice)
1 suite, 2 tests, 1 error, 0 warnings
exit 2
Every problem names the file, the line and the path to the key. Exit code 2 means a config or
schema error. Put it back with git checkout or sed -i 's/target: nope/target: api/'.
List the tests
tamesu list
tamesu list --json --filter refund
SUITE TEST TARGET TYPE TAGS
support-agent refund policy question api rest smoke
support-agent reschedule booking by voice voice livekit smoke
Check the setup
tamesu doctor validates everything, resolves every declared secret through mamori and tells
you which link of each chain answered, never the value:
export GEMINI_API_KEY=... SUPPORT_API_TOKEN=... LIVEKIT_API_KEY=... LIVEKIT_API_SECRET=...
tamesu doctor
ok config: tamesu.yaml (version 1)
ok suites: 1 file, 2 tests
ok secret API_TOKEN: env (link 1 of 1)
ok secret GEMINI_API_KEY: env (link 1 of 1)
ok secret LIVEKIT_API_KEY: env (link 1 of 1)
ok secret LIVEKIT_API_SECRET: env (link 1 of 1)
ok models: default=googleai/gemini-2.5-flash (GEMINI_API_KEY resolved)
ok chromium: Google Chrome 156 (/Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
ok livekit: ws://localhost:7880 answers HTTP 200 (targets: support/voice)
Unset a variable and the matching line becomes fail secret ...: not found in any of 1 ref(s)
with exit code 2; a secret backend that is down is fail ... provider ... failed (unavailable)
with exit code 3. Keep secrets out of the shell history with a .env file and --env-file .env:
mamori reads it, the process environment is never mutated.
Run the tests
With a model configured (genkit.plugins and models.* in tamesu.yaml, the key under
secrets:) and your agent reachable at AGENT_URL:
export GEMINI_API_KEY=...
tamesu run --filter refund
tamesu run: 1 test, output in .tamesu/runs/2026-10-31T14-20-00
PASS support-agent / refund policy question 3.4s
1 passed, 0 failed, 0 errors in 3.4s · 3 model calls, 2890 tokens, $0.0012
The run directory holds summary.json, junit.xml and, per run, transcript.json and
result.json with every assertion’s reason. A failing judge prints its reason and the last
turns under the test. See Reports and tamesu run.
The voice test runs in text mode against a LiveKit room; see the
LiveKit target for the agent it expects.
Next
- Recipes: complete projects to copy, from a REST support agent to a nightly red team, a phone IVR and an MCP server.
- Suites: every key of the YAML, generated from the schema.
- Configuration:
tamesu.yaml, secrets with mamori, interpolation. - Personas and scenarios, Assertions and Judges: how a test is written and graded.
- CLI reference: every command, flag and exit code;
tamesu lintfinds the weak tests validation accepts. - CI: run, validate and doctor in GitHub Actions, GitLab and Docker.