Replay & Fork

Re-run any agent run with zero model calls.

Point your agent’s OpenAI or Anthropic SDK at a recording and run it for real: your code, your prompts, your control flow. Every model answer comes from the tape, in the shape the SDK expects. Nothing is sent to a model provider.

Three steps

Record with content on. Create a replay. Run.

  1. Record the run with prompt and completion capture on, the default for OpenLLMetry. A replay can only serve answers that were recorded, and it says which step is missing one.

  2. Create a replay of the run. It snapshots the tape and lives for an hour. Creating one changes nothing in the store, so a read key is enough.

  3. Point the SDK at it with two environment variables and run your agent. It receives each recorded answer as an ordinary chat completion or message, streamed if it asks for a stream.

Create a replay
curl -s https://api.trazadb.com/v1/replays -H "Authorization: Bearer $TRAZA_API_KEY" \
  -d '{"run": "weather-7"}'
Engine output, from the Replay guide
{"id": "rp_ac879985abef9cba12bb342bdc3b8bd1",
 "run": "weather-7", "mode": "strict", "steps": 3, "llm_steps": 2,
 "base_urls": {
   "openai": "/v1/replays/rp_ac879985abef9cba12bb342bdc3b8bd1/openai/v1",
   "anthropic": "/v1/replays/rp_ac879985abef9cba12bb342bdc3b8bd1/anthropic"}, …}
Run the agent against it
export OPENAI_BASE_URL=https://api.trazadb.com/v1/replays/rp_ac879985abef9cba12bb342bdc3b8bd1/openai/v1
export OPENAI_API_KEY=$TRAZA_API_KEY
python weather_agent.py

# Anthropic SDK: it sends x-api-key, which replay routes accept
export ANTHROPIC_BASE_URL=https://api.trazadb.com/v1/replays/rp_ac879985abef9cba12bb342bdc3b8bd1/anthropic
export ANTHROPIC_API_KEY=$TRAZA_API_KEY

Strict by default

A regression shows up as a 409 at the step that changed.

In strict mode each request must be the recorded request: its messages are normalised and digested, then compared with the recording. A changed prompt, a different tool result or a new branch means the agent asked a different question, and serving the recorded answer would answer the wrong one. So the replay refuses, names the step, and does not consume it. The response tells both SDKs not to retry.

Loose mode serves the steps in order regardless, and records whether each call matched.

A divergence, from the Replay guide
HTTP/1.1 409 Conflict
x-should-retry: false

{"error":{"type":"replay_divergence","step":2,
  "message":"this request's messages do not match recorded step 2: the agent diverged from the recording, so replaying the recorded answer would answer a different question",
  "expected_digest":"6db28425e9e1…","got_digest":"cd1ff438bb75…"}}

Diff

Where did this run part from that one?

GET /v1/diff aligns two runs’ steps by their signatures, so an extra or missing step shifts nothing after it, then classifies each pair and names the first divergence: a different input, a different decision for the same input, a configuration change such as a model swap, or a step only one run has.

GET /v1/recall finds earlier runs that dealt with the same words, successful ones first, with a skeleton of what each did.

What differsReported as
Nothingsame
The input to the same stepchanged · input
The output, for the same inputchanged · decision
The model or a request parameterchanged · config
A step only one run hasinsert / delete · structure

Fork & Rewind

Change one step, and let the agent carry on for real.

A fork serves a different model answer or tool result at any step, then goes live: past the cut, every call answers 409 replay_live, which is the harness’s signal to send it, and every later one, to the real provider. The Python and TypeScript clients do that for you, and tag the forked run so it can be found again with how it ended and what it cost, compared with its parent.

Rewind is a live point alone: replay a long run’s first forty steps for free, then continue live from there. Traza never calls a model; a fork’s live half is your agent’s own traffic.

Fork the demo Claude Code session at its failing test run
{ "run": "11111111…", "edits": [ { "step": 5, "tool_result": "test result: ok. 3 passed; 0 failed" } ], "live_after": 5 }

Step 5 (Bash) failed in the recording. The fork holds steps 0–4, 3 of them model calls served from the tape, answers step 5 with the edit, and goes live after step 5.

Demo corpus Real output of traza-server 0.28.0 over the engine’s synthetic Claude Code and Codex transcripts (4 sessions), imported with traza-server import, recorded 2026-10-18 by scripts/demo-numbers.mjs. Synthetic runs with known outcomes, not customer data.

Tape tests

Turn the runs that went right into tests.

A tape test is a strict replay the agent must walk step for step, failing with the message, field and character where it left the path — from pytest, vitest or jest, or for every golden run at once with traza test, which writes a JUnit report for CI.

Diff across the demo map’s fatal fork

refund_happy-1 (success, 5 steps) against search_loop-0 (failure, 6 steps): first divergence at step 2, a structure change — run b has step 2 (tool:search_orders) where run a has no matching step.

Demo corpus Real output of traza-server 0.28.0 over the engine’s seeded behaviour corpus (226 runs, 1,342 spans), recorded 2026-10-18 by scripts/demo-numbers.mjs. Synthetic runs with known outcomes, not customer data.

On Traza Cloud

From a run in the console to a replay in your terminal.

The console’s Replay tab lists recent runs. Pick one and it creates the replay and shows the two environment lines for the OpenAI or Anthropic SDK, with a Python snippet, all pointing at api.trazadb.com. Use any read or full key of the project; the console never holds key secrets.

Stated plainly

What Replay does not do.

  • Tools execute live. A replay answers model calls. When the replayed model asks for a tool, your agent runs the real tool with its real side effects, unless your harness takes the recorded result from tools/next.
  • Streams are reconstructed. No instrumentation records how a provider chunked its stream, so the text is re-chunked; the text the SDK reassembles is exactly the recorded text.
  • Only chat completions and messages are replayed. The OpenAI Responses API, embeddings and legacy completions answer 400.
  • Strict mode compares messages only, not the model name, tools or temperature. A request with the recorded messages and a different model is served.
  • Replays live in memory for an hour. A restart forgets them; creating another is just another read. An erasure withdraws any replay holding erased data. A fork is a replay, under the same rules.
  • After an edit without a live point, the recording plays on loosely, answering a conversation it was not recorded in. That exercises your code down the recorded path; it is not what a model would have said.

The full Replay guide, limits includedFork & Rewind, and tape tests