CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/API & SDK
API & SDK/2026-05-31Advanced

Make Agent Failures Reproducible: Deterministic Replay and Event Sourcing

An autonomous agent that fails at 2 a.m. can't be reproduced by simply running it again. Record every nondeterminism boundary as an append-only event log and replay the failed run deterministically — with working code and operational lessons.

Claude Agent SDK13event sourcingobservability20production111replay

Premium Article

I've been building apps on my own since 2014, and across more than 50 million cumulative downloads, the failures that hurt the most were never the loud crashes. They were the quiet ones: a backend automation that failed exactly once in the middle of the night, and by morning the logs no longer told me why.

Put an autonomous agent into production with the Claude Agent SDK and this problem takes on a sharper shape. Agents depend heavily on external state. The model's output differs slightly every time, the APIs your tools call return different data as hours pass, Date.now() naturally advances, and retry branches shift with jitter and latency. In other words, "just run the failed execution again" will never lead you back to the same failure.

Both of my grandfathers were miyadaiku — traditional shrine carpenters — and I grew up watching the things they assembled last for decades. Anything built to last shares one trait: it can be inspected after the fact. That's the property I care about most when designing agents, and this article is about exactly that — designing for after-the-fact reproduction, through deterministic replay and event sourcing, from both the implementation and operations sides.

Why "run it again" can't reproduce the failure

What blocks reproduction is the set of nondeterminism boundaries scattered through an agent run. The logic itself may be deterministic, but the moments where it touches the outside world receive different values every time. From what I've observed in production, those boundaries collapse into four kinds.

First, model output: even at temperature: 0, exact reproduction isn't guaranteed, and a single different character in a tool-call argument changes the branch taken. Second, tool I/O: external APIs, databases, and files change over time. Third, the clock: any branch based on Date.now() or the date walks down a different path on each run. Fourth, randomness and retries: jittered backoff and sampling wobble between runs.

This is where many teams install an observability stack — metrics, traces, dashboards — and call it done. But that shows you statistics about what happened; it doesn't let you run one specific execution again. Postmortems need the latter. Flip the approach: record every value that passes through those four boundaries into an append-only log, and on re-execution read those values back from the log. The run becomes deterministically reproducible. That's what it means to apply event sourcing to an agent.

Defining the event log schema

Start by issuing a unique runId for each execution, then append an event with a monotonic seq every time that run crosses a boundary. The crucial part is symmetry: in "record" mode the event stores the real value, and in "replay" mode it reads that value back.

// events.ts — append-only event type and a minimal store
export type BoundaryKind = "model" | "tool" | "clock" | "random";
 
export interface AgentEvent {
  runId: string;
  seq: number;            // strictly increasing within a run
  kind: BoundaryKind;
  key: string;            // logical key of the call (e.g. "tool:fetch_orders")
  input: unknown;         // input at record time (used for matching)
  output: unknown;        // the real value the boundary returned
  tokensIn?: number;      // model events only
  tokensOut?: number;
  costUsd?: number;
  ts: string;             // ISO8601 — record time, not the clock's true value
}
 
export interface EventStore {
  append(e: AgentEvent): Promise<void>;
  load(runId: string): Promise<AgentEvent[]>;
}

In production, keeping the EventStore strictly append-only is the lifeline. Rewriting it midstream destroys reproducibility. I run two implementations: JSON Lines (one event per line) in object storage for production, and a plain array in development. Always carry kind and key in the schema — they're the keys the replay step uses to verify "same order, same call."

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Identify the nondeterminism boundaries (model output, tool I/O, clock, randomness) and record them as an append-only event log, with concrete code
A replay harness that reproduces a single failed run deterministically and entirely offline
An operational workflow that attributes cost and tokens per run from the same log
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API & SDK2026-06-23
When Claude API Prompt Caching Quietly Stops Hitting in Production — Field Notes on TTL and Measured Savings
Prompt caching works beautifully the day you ship it, then quietly stops hitting in production. The five things that break the prefix, how to choose between 5-minute and 1-hour TTL, and how to measure real savings from usage instead of guessing.
API & SDK2026-06-18
When Your Claude API Response Cache Returns Stale Answers and Near-Miss Wrong Ones — Field Notes on Freshness and False-Hit Suppression
A Claude API response cache improves latency and cost immediately, but the problems that hurt in production are not average hit rate — they are stale hits and semantic false hits. Here is the key design, freshness management, false-hit suppression, and observability that keep a cache honest.
API & SDK2026-06-16
PII Masking for Claude API Lives or Dies on the Ledger — Restore, Encrypt, Measure
The hard part of masking PII before Claude API isn't detection — it's operating the token ledger you restore from. Encrypted storage, multi-instance sharing, and a daily leak-rate loop, with working code.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →