AI Agent State Checkpointing: Resume Long Tasks Without Repeating Side Effects
Long-running agents will crash, time out, and lose context. Durable checkpoints let them resume safely without sending the same email or charge twice.
If an agent cannot explain what already happened, it cannot resume safely. AI agent state checkpointing turns a fragile chain of prompts into a durable workflow that can survive process crashes, model timeouts, deployments, and human approval delays.
The hard part is not saving the chat transcript. It is recording business state: which intent was accepted, which tool calls began, which effects committed, what evidence came back, and what step is safe next.
Prerequisites
You need a durable database, unique workflow and step IDs, structured tool calls, and an executor that supports idempotency keys where possible. Use a transaction-capable store for the workflow log. Object storage can hold large artifacts, but it should not be your only source of truth.
Step 1: model work as explicit states
Do not infer progress by rereading natural-language messages. Define states such as planned, awaiting_approval, executing, verifying, completed, and failed_retryable.
type WorkflowState = {
workflowId: string;
version: number;
status: "planned" | "awaiting_approval" | "executing" |
"verifying" | "completed" | "failed_retryable";
currentStep: number;
inputHash: string;
policyVersion: string;
updatedAt: string;
};
Expected result: operators can answer “where is it?” without reconstructing the model’s reasoning.
Step 2: separate intent from effects
Store a normalized step before executing it.
type StepRecord = {
stepId: string;
workflowId: string;
kind: string;
argumentsHash: string;
idempotencyKey: string;
status: "prepared" | "started" | "committed" | "verified" | "failed";
externalOperationId?: string;
attempt: number;
};
The checkpoint should contain references to artifacts and tool responses, not hidden chain-of-thought. Save the concise facts needed for resumption and audit.
Step 3: write before you act
Use a write-ahead pattern:
- Insert the prepared step and idempotency key.
- Commit the database transaction.
- Execute the external action.
- Store the external operation ID and result.
- Verify the effect.
- Mark the step verified.
A crash between steps three and four creates uncertainty. On resume, query the external system using the idempotency key or operation ID. Never blindly repeat the action.
Step 4: make every side effect idempotent
An idempotency key should represent one business intent, not one retry.
const key = sha256(canonicalJson({
workflowId,
step: "create_invoice",
customerId,
lineItems,
currency,
}));
Send the same key on every retry. If the provider lacks native support, create a local outbox with a uniqueness constraint. For emails, store a message fingerprint and provider message ID. For file writes, use content hashes and atomic rename. For deletes, verify the resource state before and after.
Expected result: retrying a committed request returns the original result instead of duplicating the effect.
Step 5: use optimistic concurrency
Two workers may resume the same job. Protect state transitions with a version number or lease.
UPDATE workflows
SET status = 'executing', version = version + 1, updated_at = now()
WHERE workflow_id = $1 AND version = $2 AND status = 'planned';
If no row changes, another worker won. Do not continue. Leases need expirations and fencing tokens so a slow worker cannot write after its lease has been replaced.
Step 6: checkpoint model context intentionally
Store a compact resume packet:
- user goal and immutable constraints;
- accepted plan and completed-step evidence;
- unresolved decisions;
- artifact IDs and hashes;
- current policy and prompt versions;
- safe next action.
On resume, rebuild context from this packet and authoritative system data. Do not replay every old tool output; stale or hostile content can regain influence.
Step 7: verify before declaring completion
A tool returning 200 does not prove the intended outcome. Add a separate verification step that reads public or authoritative state.
await runStep("publish", publishPost);
await runStep("verify_public_url", async () => {
const page = await fetch(expectedUrl);
if (!page.ok || !(await page.text()).includes(expectedTitle)) {
throw new RetryableError("publication not visible");
}
});
Only the verified state should trigger user-facing completion.
Recovery decisions
On restart, classify the current step:
prepared: safe to execute with its idempotency key;started: inspect the external system before retrying;committed: run verification;verified: advance;failed: retry only if policy and retry budget allow.
If an irreversible action has unknown status and cannot be queried, stop for human review. Guessing is worse than delay.
Common pitfalls
Saving only conversation history leaves effects ambiguous. Updating state after a call without a write-ahead record creates the classic crash gap. Generating a fresh idempotency key per attempt defeats deduplication. A global “completed” flag hides partially completed batches. Finally, compensation is not rollback: sending a refund after a charge creates two auditable events and may itself fail.
A practical test matrix
Kill the worker before and after each external call. Duplicate queue deliveries. Delay one worker until its lease expires. Return a success response while withholding the visible effect. Change the prompt version halfway through. Your system should either resume correctly or stop with a precise, reviewable uncertainty.
The goal is not uninterrupted execution. It is controlled continuation: after any interruption, the agent knows what is durable, what is uncertain, and which next action cannot duplicate harm.
Sources
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
LLM Timeout Budget Propagation: Stop Nested AI Calls From Outliving the User Request
One slow model call can trigger a chain of zombie retries. Propagate a shared deadline through agents, tools, queues, and providers to bound latency.
Policy as Code for AI Agents: Turn Safety Rules Into Testable Runtime Controls
Safety prose cannot stop a tool call. Encode agent permissions as deterministic policy, test every branch, and log decisions your team can audit.
AI Agent Tool Contract Testing: Catch Breaking Changes Before Production
Agents fail in strange ways when tool schemas drift. Contract tests make names, arguments, permissions and error shapes part of every deployment gate.
Tags
> Stay in the loop
Weekly AI tools & insights.