Using Anthropic's Claude Agent SDK with Catalyst's Durable Execution
The Claude Agent SDK persists conversation state but not execution position. Diagrid Catalyst adds durable execution underneath the SDK, turning every LLM call and tool invocation into a checkpointed workflow activity that resumes exactly where it failed.
You're running a Claude Agent SDK agent in production. The main loop has just dispatched three subagents in parallel. One returned with a file edit. The second is mid-shell-command. The third is still streaming. And right then, the container running your process gets a SIGTERM from the scheduler, a rolling deploy, a spot preemption, whatever it is.
You have session persistence turned on. So when the process comes back up, things look fine at first. The conversation is intact. Messages, tool calls, tool results, all are there.
Then you look closer. The subagent that was mid-shell-command? It never finished. There's no record of what it was actually doing when the SIGTERM hit. The parallel dispatch that had three branches in flight? Only one made it back into the transcript. The loop doesn't know where it was; it only knows what it said.
That's the mismatch. The SDK persists the conversation, but not the position inside the current agent loop. Resuming a session picks up the thread; it doesn't pick up execution.
So the question this article is about: what does it take to make a Claude Agent SDK agent survive a crash and resume from where it stopped, not from where the conversation left off?
What the Claude Agent SDK ships, and what it doesn't
The Claude Agent SDK is Anthropic's runtime for building autonomous agents in Python and TypeScript. It's the same harness that runs Claude Code, exposed as a library. You call query(), hand it a prompt, and it drives the loop: Claude reasons, calls tools, sees results, decides what to do next, over and over, until the task is done.
You get a lot in the box:
- The agent loop itself: the SDK orchestrates each turn, executes tools, manages context, and streams messages back to you.
- Built-in tools (bash, filesystem, web search, code execution, computer use) that the agent can invoke without you wiring each one up.
- Subagents as tools which spawn sub-loops for isolated sub-tasks, each with its own context window.
- Hooks that fire at lifecycle points (PreToolUse, PostToolUse, PostToolUseFailure) for approvals, logging, and guardrails.
- A permission system that gates which tools can run, with support for interactive approvals.
- Session persistence: every message, tool call, and tool result within a run gets written to disk, keyed by a session ID you can resume or fork later.

Fig 1: What the Claude Agent SDK's session store captures, and what it leaves out.
That last one is the piece worth being precise about.
Session persistence saves conversation state. When you resume a session, the SDK reloads the message history, hands it back to Claude, and Claude continues from the last message. If the last message was Claude thinking "I should call the bash tool with this command," resumption puts you right back at that thought.
What it does not save is execution position inside the loop. It doesn't know whether an issued tool call actually completed, whether a subprocess is still mid-run, whether a subagent was mid-stream, or whether a parallel branch was still in flight. When you resume, Claude re-reads the transcript and decides what to do next, including, potentially, re-running a tool call that already happened.
This isn't a shortcoming. It's scope. Anthropic makes a clean distinction between the Agent SDK and Managed Agents, where Anthropic hosts both the loop and the sandbox. Durable execution is one of the layers you're expected to bring yourself when you go the SDK route. The docs are explicit that sessions persist the conversation, not the filesystem. The same principle applies to the state of the loop.
What durable execution adds that sessions alone don't
The line worth drawing clearly: session persistence is storage of a conversation. Durable execution is a runtime guarantee about the loop.
A workflow engine treats each tool invocation and each LLM call as a checkpointed step, an activity, in workflow terms. When your process crashes and restarts, the engine doesn't re-read the transcript and hope Claude re-derives the same plan. It replays a recorded log of what actually happened. Every activity, in order, with its inputs and results until it reaches the last one that completed. Then it picks up from exactly there.
The difference shows up the first time you crash mid-execution.

Fig 2: (Left) Session resume replays the transcript and risks re-running completed steps. (Right) Durable-execution resume replays the activity log and retries only the failed step.
A session-based resume says: "Here's the conversation as of the last flush. Figure out what to do." A durable-execution resume says: "You were on step 7. Step 7 didn't finish. Retry step 7 with the same inputs. Steps 1–6 already completed, and their results are right here." No re-inference. No paid-for LLM calls run twice. No tool actions repeated on the outside world.
The mechanics of how this works underneath (event sourcing, deterministic replay, the split between orchestrator and activity) are the whole point of Dapr Workflows, and the durable agents article walks through them in depth. What matters for the framing here is the shape of the promise: the loop becomes something the runtime can resume from its last checkpoint, without your agent code being aware of it.
Which is exactly the framing that matters for what comes next.
Diagrid Catalyst is a reliable and secure platform for running agentic workloads in production, with the Dapr runtime, state stores, and message brokers managed for you. It runs underneath the Claude Agent SDK. The agent code stays the same.
The integration: what changes in the code
Here's the thing that surprises people: almost nothing.
The agent definition stays the same. The tools stay the same. The ClaudeAgentOptions object, the system prompt, the model configuration, the way you consume messages, all standard Claude Agent SDK, untouched. What changes is two things.
First, install the Diagrid extension for Claude Agent SDK:
pip install "diagrid[claude_agents]"Second, wrap the agent with the Diagrid runner instead of calling query() directly. Here's the shape of it, taken from the Diagrid Claude Agent SDK quickstart:
from claude_agent_sdk import ClaudeAgentOptions, tool
from diagrid.agent.claude_agents import DaprWorkflowAgentRunner
@tool("step_one_search", "Search for options.", {"event_type": str})
async def step_one_search(args):
text = f"Found 3 {args['event_type']} options. Now call step_two_compare."
return {"content": [{"type": "text", "text": text}]}
# ... two more tools defined the same way ...
options = ClaudeAgentOptions(
system_prompt="Execute the tools in sequence...",
model=os.environ.get("CLAUDE_MODEL", "claude-sonnet-4-6"),
)
runner = DaprWorkflowAgentRunner(
name="crash-recovery-demo",
options=options,
tools=[step_one_search, step_two_compare, step_three_confirm],
max_iterations=10,
)DaprWorkflowAgentRunner takes the same ClaudeAgentOptions and tool functions you'd hand to the SDK directly. What it does with them is different: it hands the loop over to Dapr Workflows underneath. At runtime, each LLM turn and each tool invocation is modeled as a workflow activity. A step that runs once, records its result, and can be replayed from that recorded result on restart. Catalyst persists that state to a state store you configure (Postgres, Redis, CosmosDB, whichever fits) after every activity.

Fig 3: DaprWorkflowAgentRunner wraps the SDK: every LLM call and tool invocation becomes a checkpointed workflow activity, with state persisted to a store you own.
The Claude Agent SDK still runs the agent loop. It still calls tools. It still streams messages. But every one of those steps is now inside a checkpointed workflow, and the workflow's state lives outside your process — in a store you own.
For a full working example, including the diagrid CLI setup, the crash test, and the observable resume, walk through the Diagrid Claude Agent SDK quickstart end to end.
What the developer gets in return
Wrapping the runner isn't the payoff. It's the setup. Here's what that setup buys you.
- Automatic failure recovery. A crashed agent doesn't need custom recovery logic in your code. When the process comes back up, the workflow engine sees an in-flight execution, replays the recorded activities to reconstruct state, and resumes at the exact tool call that was interrupted. No re-inference of prior steps. No repeated tool calls with side effects on the outside world. The next thing the agent does is the next thing it was going to do.
- Deterministic replay for debugging and audit. Because every LLM call and every tool invocation is checkpointed, a past execution can be re-run without touching the model or the tools. The workflow replays with recorded results, giving you a bit-for-bit reproduction of what actually happened. That turns "the agent did something weird last Tuesday" from a lost cause into a repeatable investigation. You can step through the same execution, inspect intermediate state, and see the exact tool arguments that produced the odd output.
- Cross-cloud portability. The state and runtime layer is pluggable. State can live in Postgres on AWS today, CosmosDB on Azure tomorrow, or your own Postgres in a private datacenter — same agent code, same workflow definitions. You're not tied to a hosted execution plane you can't move off of, and you're not rewriting the storage layer when the platform decision changes.
- Framework-agnostic underneath. The same durability layer works for the other frameworks Diagrid supports. LangGraph, CrewAI, Strands, OpenAI Agents, Google ADK, PydanticAI, and Deep Agents and others all wrap the same way. If a team standardizes on Diagrid Catalyst for durability, they don't have to standardize on one SDK to get it. A team that picks the Claude Agent SDK for its subagent model can sit alongside a team that picks LangGraph for its graph semantics, and both get the same runtime guarantees. The durability decision and the framework decision come apart.
Where to go next
The Claude Agent SDK gives you conversation continuity. The thread survives across sessions. Diagrid Catalyst adds execution continuity. The loop survives across crashes. The code change to get there is a pip install and a runner wrapper.
The natural next question is coordination. Once a single agent's execution is durable, how do multiple agents talk to each other reliably? Sub-loops become peer agents, a supervisor delegates to specialists, and the durability guarantees need to hold across the whole graph, not just inside any one node.
To go deeper into the underlying concepts, start with the Dapr University Dapr Agents course. It covers Dapr Workflows, activities and orchestrators, the mechanics of deterministic replay, and how durable agents are built end to end. It's the same runtime running underneath your Claude Agent SDK code, unpacked step by step.