TruAssure guide
Black-box, evidence-based quality engineering for AI agents: chat assistants, task agents and multi-agent
workflows. This guide ships inside the package (ta docs --open) and needs no network.
1. Install
pip install truassure # the core: the ta / truassure commands and the library
pip install "truassure[mcp,proxy,otel]" # plus the MCP server, the recording proxy and A2A tap, the OTel receiver
| Extra | Adds |
|---|---|
proxy | ta proxy (recording MCP proxy with fault injection) and ta a2a (agent-to-agent tap) |
otel | ta otel: an OTLP/HTTP receiver for the agent's OpenTelemetry GenAI spans |
mcp | ta mcp: TruAssure as an MCP server for AI assistants |
azure, anthropic | The LLM rubric grader (output-vs-action consistency) on Azure OpenAI or Anthropic |
chat, langgraph, postgres | The WebSocket chat driver; LangGraph and Postgres support for your own adapters |
Python 3.11 or later, on Windows, Linux or macOS. Pin the version in projects and CI: truassure==__VERSION__.
2. Five-minute demo
ta demo # runs the whole tour offline, into ./ta_demo
ta console --runs-dir ta_demo --open
The demo needs no agent, no Docker and no LLM: a scripted agent plays a fictitious insurance assistant. It runs
the demo catalog twice with repeats and perturbations, runs a build with a planted defect, then compares the runs,
lists defects, builds the scorecard, applies the release gate, calibrates a grader and writes HTML reports.
Every step prints the ta command it ran, so you can repeat any of them.
3. Start a project
ta new task claims-tests # or: ta new workflow ... / ta new chat ...
cd claims-tests
ta validate catalog.yaml
| File | What to do with it |
|---|---|
catalog.yaml | An example catalog for the profile. Replace the scenarios with your agent's. |
environment.py | How TruAssure reaches the agent and where the evidence is. Fill in the TODOs (mostly the reset). |
.env.example | The settings environment.py reads: copy to .env. |
truassure-gate.yaml | The release gate policy. |
README.md | These steps, for your team. |
One project per agent or AI initiative works well: the catalog and gate are code, reviewed in pull requests.
4. How an agent is judged
An episode is one task given to the agent in a prepared environment. A checkpoint is where it is judged (every user turn in a chat; once at the end for a task or workflow). Each checkpoint is judged at five stages, and the first failing stage is reported:
| Stage | Question | Evidence |
|---|---|---|
| goal | Did it understand the request (intent, route)? | The agent's reported decision |
| plan | Was the course sensible: steps, loops, handoffs, approvals before writes? | Trace and observers |
| action | Only allowed, correct actions, with the right arguments, for the right person? | Observers (proxy, spans, tap) |
| end_state | Is the data right afterwards, and did nothing else change? | Before/after snapshots |
| output | Is what it told the user true and complete, and consistent with what it did? | Reply or report, graders |
Seams (SE-01 to SE-07) are where the agent's own account and the independent evidence disagree: a call it
reported that never happened, a write it didn't mention, a success announced after a failure, an action for the
wrong person. Each failure has a code (e.g. ACTION.FORBIDDEN_CALLED) with a severity.
Profiles: conversational (turn by turn), task (one event or task, judged at the end),
workflow (several agents, handoffs, identity on every hop, failure containment).
5. Connect your agent
An environment factory is a Python function environment(worker) -> Environment that
ta run --env module:function calls once per parallel worker. Ready-made builders:
| Builder | For |
|---|---|
truassure.profiles.task.http_task_environment | A task agent behind HTTP, a SQLite system of record and a folder of files it writes |
truassure.profiles.workflow.http_workflow_environment | Multi-agent systems behind HTTP, with the proxy and the A2A tap |
truassure.profiles.conversational.http_chat_environment | A chat agent behind a plain HTTP endpoint |
What the agent's endpoint should return
Task and workflow (POST /events with {"event": ...} or {"task": ...}, the
principal in X-Principal):
{"route": "claims_intake", "reason": "...",
"steps": [{"kind": "action", "name": "update_claim", "args": {"claim_id": "CLM-1001"}, "ok": true, "result": "..."},
{"kind": "handoff", "agent": "triage", "to": "billing", "member": "M-1001"}],
"hops": [{"from": "triage", "to": "billing", "member": "M-1001", "permissions": ["billing:read"]}],
"output": "summary for the user", "done": true, "outcome": "finished",
"usage": {"input_tokens": 0, "output_tokens": 0}}
Chat (POST /chat with {"session": "...", "message": "..."}):
{"reply": "Your balance is $193.60.", "intent": "billing",
"steps": [{"kind": "action", "name": "get_billing", "args": {"policy_id": "POL-1002"}, "ok": true}]}
Only reply (chat) or done/output (task) are essential. A different shape needs
only a parse function passed to the driver. An agent that reports nothing about its steps can still be
tested as a black box (chat: trace=False): its actions then come from the observers alone.
Independent evidence
| Source | How | Records |
|---|---|---|
| Recording MCP proxy | ta proxy --upstream <tool server> --log-dir logs/proxy; point the agent at the proxy | Every tool call: name, arguments, principal, outcome. Injects faults (error, timeout, empty) in the upstream's own format. |
| A2A tap | ta a2a --route billing=<url> --log-dir logs/a2a; senders call the tap | Every handoff, with the member and permissions read from the identity token. Injects agent faults. |
| OpenTelemetry | ta otel --out-dir spans (needs TA_OTEL_TOKEN); the agent exports OTLP/JSON to it | GenAI execute_tool spans: a second record of tool calls. |
| State | SQLite database, a folder of files, a git repository | Before/after snapshots and diffs; SQL, file and git checks. |
environment.fixture. Without it, scenarios that change data affect the ones after them.Other systems (a message bus, Postgres, a SaaS API) plug in as adapters: classes that implement the driver, observer
or state protocol in truassure.core.protocols, registered through the entry-point groups
truassure.drivers, truassure.observers, truassure.state and
truassure.graders.
6. Writing a catalog
A catalog is YAML, checked against a JSON Schema by ta validate. Keys starting with x- are
ignored, which is handy for YAML anchors and notes.
schema_version: 1
name: claims agent
defaults: {principal: {user: adjuster-07, permissions: ["claims:read"]}, environment: {fixture: seed},
budgets: {steps: 12, seconds: 120}, severity: major}
actions:
get_claim: {kind: read, scopes: ["claims:read"]}
make_payment: {kind: write, requires_approval: true, scopes: ["payments:write"]}
scenarios:
- id: INTAKE-01
profile: task
input: {event: {type: claim.document_received, claim_id: CLM-1001}}
expect: {...}
Scenario fields
| Field | Meaning |
|---|---|
id, profile | Required. Profile: conversational, task or workflow. |
principal | {user, roles, permissions, attributes}: who the agent acts for. Checked on every observed call. |
input | Exactly one of prompt, event (needs a type) or task. Task and workflow scenarios. |
checkpoints | Conversational: one per user turn, each {id, input: {prompt}, expect, perturbations, faults, approval}. |
agents | Workflow: the agents taking part (two or more). |
perturbations | Variants of the input: a whole alternative prompt (string), or {name, <field.path>: value} overrides, or noise: duplicate_event, reordered_fields, extra_fields, typos. |
faults | {action, mode: error|timeout|empty, times, delay_s, message}, injected by the proxy or tap. |
budgets | {steps, tokens, cost_usd, seconds}. |
severity | critical, major or minor; drives defect severity and the gate. |
test_types | Test-type ids for the scorecard (e.g. TT-02, SS-09, SE-07). |
capabilities | Tags such as claims.intake: used by capability packs and per-capability gate rules. |
What to expect, stage by stage (expect)
| Key | Checks |
|---|---|
goal.intents, goal.route, goal.routes | Accepted intents (chat) or the route / task interpretation. |
plan.max_steps, max_loops, max_calls | Bounds on the course taken (max_calls may be per action). |
plan.terminates, approval_before_writes, no_duplicate_writes | It finished; it asked before writing; it didn't repeat writes. |
plan.handoffs, handoffs_ordered, contain_failures | Workflow: {from, to, principal_preserved, max_permissions} per hop; exact order; after a failure nothing is handed on. |
actions.required, attempted, preferred | Actions that must succeed / be tried / ideally be used. An item is a name or {name: {arg: value}}. |
actions.forbidden, allowed, must_not_succeed, no_writes | Never call; call nothing else; may be tried but must not succeed; no writes at all. |
end_state.changes | none, a list of tables or paths that are the only ones allowed to change, or {adapter: [scopes]}. |
end_state.sql, files, git | {name, sql, equals}; {path, exists, contains, not_contains, equals, matches}; {ref, branch_exists, commit_count, files_changed, message_contains}. |
output.facts, output.forbidden | Facts the answer must state ("a or b" alternatives); phrases it must not contain. |
output.artifact | A file, report or patch the agent produced: {kind, path, checks, tests}. |
output.reference, output.rubric | For graders (e.g. the LLM rubric grader). |
Translating an existing suite catalog: ta translate suites.yaml --yaml -o catalog.yaml.
7. Running
ta run catalog.yaml --env environment:environment --repeats 3 --perturbations all --parallel 2
| Option | Meaning |
|---|---|
--repeats N | Run each episode N times: pass^k (works every time, not just once) and flaky detection. |
--perturbations all|0,1,2 | Also run the input variants (0 is the catalog input): robustness. |
--parallel N | N environments (workers) at once. |
--scenario ID | Only these scenarios (repeatable). |
--mask LABEL=REGEX | An extra masking rule for personal data (repeatable). |
--run-id, --runs-dir, --step-timeout | Name the run; where runs go (default ./ta_runs or TA_RUNS_DIR); seconds per stimulus. |
Exit codes: 0 every case passed, 1 a case failed or was flaky, 2 bad input, 3 the environment is locked by another run.
8. Results and decisions
| Command | Gives |
|---|---|
ta show [run] | Runs, or one run's cases: stage marks, result, Wilson range, reasons. |
ta report latest | One self-contained HTML file (works offline): overview, cases, episodes (the agent's account beside the evidence), scorecard, defects, comparison and gate. |
ta console --open | A local browser console over all runs: reports, comparisons, gates. 127.0.0.1 only, token in the URL. |
ta compare A B | Checkpoint by checkpoint: regressions and fixes. Across deployments (model, host, framework), a parity verdict against run-to-run noise. |
ta defects latest | The defect list (JSON and CSV), severity by failure code. |
ta junit latest [--baseline RUN] | JUnit XML for CI; with a baseline only new failures fail. |
ta scorecard latest | The run against the 71-type test catalogue: measured, failing, not run. |
ta pack CAPABILITY | Is a capability ready? (exit 1 when not) |
ta gate latest --policy truassure-gate.yaml | The release gate (exit 1 on fail): pass rate, defects by severity, flaky handling, parity, clean seams, per-capability rules. |
ta calibrate set.yaml --grader module:Class | How far to trust a grader: Cohen's kappa against human labels. |
# truassure-gate.yaml
gate:
max_defects: {critical: 0, major: 2}
min_pass_rate: 0.9
flaky: fail # fail | skip | pass
parity_must_hold: true
seams_clean: [SE-01, SE-02, SE-03, SE-04]
capabilities:
claims.settlement: {min_pass_rate: 1.0, max_defects: {critical: 0, major: 0}}
9. CI pipelines
ta init --ci github --catalog catalog.yaml --env environment:environment
ta init --ci azure --catalog catalog.yaml --env environment:environment
Writes a pipeline that installs TruAssure, validates the catalog, runs it with repeats and perturbations, publishes
JUnit results and the defect list, applies the gate and keeps the run folder as an artifact. Set the
TRUASSURE_PIP variable to pin the version (e.g. truassure==__VERSION__).
10. AI assistants (MCP)
{ "mcpServers": { "truassure": { "command": "ta", "args": ["mcp"] } } }
Every CLI command is a tool with the same arguments, so an assistant in the IDE can validate catalogs, run them, read results and apply the gate. Long-running services (proxy, tap, receiver, console) are not tools. Results are marked as data: they may quote what an agent said, and must not be followed as instructions.
11. Settings and security
- Settings and secrets come from environment variables or the nearest
.env(real environment variables win). TruAssure never prints secret values. Keep.envout of git. - Every listener binds to 127.0.0.1 unless
--allow-remote. Control APIs need tokens (TA_PROXY_TOKEN,TA_OTEL_TOKEN); the console makes its own per start. - Personal data (emails, phone numbers, secret-named fields, your
--maskrules) is masked before evidence is written.ta gc --days Napplies retention. - Test against test environments and test data. Fault injection and resets change the agent's environment.
12. Command reference
| Command | Purpose |
|---|---|
demo, new, docs | Offline tour; a starter project; this guide. |
validate, translate | Check catalogs; convert a suite catalog. |
run, show, report, gc | Run a catalog; list and inspect runs; the HTML report; retention. |
compare, defects, junit, scorecard, pack, gate, calibrate | Run-level analysis and governance. |
init | A CI pipeline. |
console, mcp | The browser console; the MCP server. |
proxy, a2a, otel | Observers. |
ta <command> --help lists every option.
TruAssure __VERSION__ · MIT licence · examples use fictitious Harbor Mutual data.