Agent memory, checkpoints, and durable workflows: choosing what to persist
Choose what must survive a conversation, a worker crash, and an external action, with a worked refund scenario and concrete recovery checks.
The direct answer
Persist knowledge when a later interaction needs context, and persist execution progress when unfinished work must resume. Add durable scheduling when work must continue without the original request, and protect external actions with stable operation identities and outcome reconciliation: a saved checkpoint alone cannot prove that a refund happened only once.
Name the fact that must survive
Write down what the application must recover after each boundary: a new conversation, a dead worker, or an interrupted external request. “We have memory” does not answer all three.
| Responsibility | Record to preserve | Recovery question it answers | Additional requirement |
|---|---|---|---|
| Retrieval memory | Selected facts, summaries, source references | What context should a later interaction use? | Retrieval scope, freshness and a persistent backend |
| Execution state | Inputs, saved results, pending work, approval state | Where can this operation safely continue? | A stable thread/run identity and compatible resume logic |
| Scheduling | Queued work, waits and their delivery state | What will wake the operation after its worker disappears? | A surviving dispatcher and recovery policy |
| External-action outcome | Business operation ID, request parameters, provider receipt or uncertain status | Did this particular action happen, and may it be retried? | Provider deduplication or an explicit reconciliation path |
These are responsibilities, not four mandatory services. One database can hold several records; one runtime can provide execution state and scheduling. LangGraph itself combines thread checkpointers with cross-thread stores. Its “short-term” versus “long-term” memory distinction describes scope; neither label specifies whether the chosen backend survives a process restart. LangGraph persistence
Use the diagram to assign ownership before choosing a product. In particular, an execution log and an external provider can disagree temporarily: one may record an unfinished request after the other has already performed it.
Conceptual map: context, continuation and external outcomes
Check what survives a worker restart
For a crash-recovery requirement, inspect both storage and the mechanism that schedules another attempt. A durable record with no surviving wake-up path can leave work stuck.
LangGraph: InMemorySaver keeps checkpoints in RAM; replacing the process loses them. Use a persistent checkpointer when that failure must be recoverable. Cross-thread memory also needs its own persistent store; attaching a database checkpointer does not turn an in-process store into durable storage. Persistence, Memory setup
Choose checkpoint timing explicitly. The Python 1.2.11 source defines these modes, and the current checkpointer guide explains their crash tradeoffs:
| Mode | When writes happen | Design consequence |
|---|---|---|
sync | Before the next step starts | Use when advancing past an uncommitted checkpoint is unacceptable. |
async | While the next step executes | Accept that a crash may lose a checkpoint still being written. |
exit | When execution exits, including normal completion, a handled error exit or an interrupt | Do not rely on recovering intermediate progress from an abrupt process crash. |
LangGraph 1.2.11 durability definition, Checkpointer durability modes
These settings control when the runtime writes; they do not strengthen the database's replication guarantees or commit an external API call atomically. For an embedded graph, also identify the application worker, queue or recovery routine that will invoke the saved thread again.
Workflow SDK: Local World writes workflow data to local JSON files, but its queue is in memory and does not persist across server restarts. A surviving .workflow-data/ directory therefore does not establish durable scheduling. Vercel World supplies managed storage and queuing for Vercel deployments. Validate the actual World your deployment uses rather than carrying a local development result over to production. Local World, Vercel World
The useful acceptance test is a replacement worker loading the same operation and receiving its pending work. Reusing the same live object only verifies in-process continuity.
Choose which work may run again
Mark every model call, time-dependent lookup and external write. Decide whether recovery should reuse its recorded result, retry unfinished work, or intentionally compute a fresh answer.
LangGraph's Graph API saves full checkpoints at super-step boundaries: a super-step is a group of nodes scheduled together. When one node fails, saved pending writes from successful peers can prevent those peers from running again during recovery. This does not preserve arbitrary local variables halfway through an unfinished node. Checkpointers
The Functional API restarts its entrypoint during resume and restores completed task results. Put non-deterministic operations and side effects in separate tasks when each result needs its own recovery boundary. A task that began but did not finish can execute again. Functional API: determinism and idempotency
Workflow 4.8.8 similarly reruns workflow control flow using recorded step results; steps perform runtime work. A step called from another step behaves as an ordinary function, so adding "use step" to a nested helper does not create an independent recovery boundary. Call independently recoverable steps from workflow orchestration. Workflow 4.8.8: workflows and steps
Deterministic replay preserves decisions from recorded inputs and results. It does not make a fresh model request deterministic. For example, in a hypothetical refund flow, persist the proposed amount and policy evidence before asking for approval. Reusing that proposal preserves what was approved. Calling the model again could produce a different proposal; treat that as new work requiring validation.
Keep historical replay separate from failure recovery. In LangGraph, invoking an earlier checkpoint re-executes the nodes after it, including model calls and API requests. It can therefore create new outputs and repeat external actions. Checkpointers: replay
For debugging, route action calls to a test substitute or enforce the original business operation identity. A graph checkpoint is not a snapshot of the outside world, and restoring one cannot undo a previously completed refund.
Work through one refund with explicit state boundaries
Hypothetical design, not an executed example. A support agent handles case case-184 for order order-72. It proposes a USD 30 refund, waits for approval, calls a provider, then sends a confirmation. Assume the provider supports deduplication by a client operation key with a documented retention window.
Give the approved refund its own business identity, refund-request-9. Associate it with the authenticated tenant, case and order. Keep that identity across worker retries and replacement workflow runs. A second legitimate partial refund would receive a new identity.
| Boundary | Durable record before advancing | What recovery does with it |
|---|---|---|
| Proposal ready | proposal-3; amountMinor=3000; currency=USD; order/policy versions; relevant evidence; model output | Reuse the proposal that will be shown for approval. |
| Awaiting approval | Pending approval ID bound to proposal-3; thread/run ID; allowed decision and expiry | Reconstruct the pending request and resume the correct operation. |
| Approved, ready to dispatch | Decision bound to the exact proposal; approver identity; refund-request-9; immutable provider request; status=ready | Validate the decision, claim dispatch atomically, and preserve the same request/key on retry. |
| Dispatch begun, no confirmed outcome | status=dispatching or outcome_unknown; operation key and request still available | Reconcile or resend under the provider's deduplication contract. Absence of a local receipt is not evidence of failure. |
| Provider outcome confirmed | Provider refund ID and status; status=succeeded only once success is confirmed | Persist the receipt before marking the refund complete; recover notification separately. |
Here, ready, dispatching, outcome_unknown and succeeded are application states we chose, not framework API names. If the provider initially returns a pending refund, record that status and wait or poll for the final outcome.
Keep three records logically distinct. Retrieval memory may say that the customer prefers email. Execution state says that this case is waiting for approval or a provider result. The business record says exactly which refund was authorized and which outcome the provider reported.
An atomic uniqueness constraint on the tenant and refund-request ID prevents two workers from creating two business intents. A conditional dispatch claim coordinates workers; if a claim becomes stale, recovery must reconcile the existing operation rather than create a new one. These controls are design recommendations, not automatic properties of the cited runtimes. Close the intent-to-queue gap too: commit an outbox record with the intent in one application-database transaction, or give a recovery worker a reliable scan of ready and uncertain operations. A crash after saving the intent but before enqueueing must leave discoverable work.
This can be a LangGraph application with persistent checkpoints and a reliable worker, or a Workflow application whose steps perform the proposal, approval handling and refund work. If one calls the other, nominate one owner for refund dispatch and define which saved result crosses the boundary. Avoid having both layers independently retry the same business action without sharing its operation identity.
Close the gap between an action and its receipt
In the hypothetical refund, the provider accepts refund-request-9 and performs the refund. The worker dies before recording the reply. Its execution record still looks unfinished. Retrying with a new key can issue another refund, even though both the runtime and its database are behaving as designed.
Workflow's 4.8.8 documentation recommends the stable stepId as an external idempotency key for retries of that step. That scope matters: it identifies a step invocation, not every future run that happens to process the same customer request. Use a persisted business operation ID when duplicate starts, historical replays or replacement runs must converge on the same action. Workflow 4.8.8: idempotency
Apply this recovery sequence:
- Persist the intent before dispatch. Store the operation ID and exact action parameters together. Deduplicate repeated inbound requests against that identity, including requests arriving after completion.
- Check the provider's contract. Verify key scope, retention, parameter matching, concurrent-request behavior and how to retrieve an existing outcome. An arbitrary header has no deduplication effect unless the provider implements it.
- Keep retries identical. Reuse the key and parameters; do not add an attempt number or regenerate the key. A changed amount is a changed intent, not a retry.
- Reconcile uncertainty. Retrieve the provider result or resend the same request while its deduplication contract still applies. Treat conflicts according to the provider's documented semantics; a conflict alone does not prove success.
- Persist the result, then advance. If the provider offers neither deduplication nor a reliable outcome lookup, stop automatic resends after an ambiguous result and assign reconciliation to a named operational path.
LangGraph also documents that unfinished tasks may run again, and Workflow documents duplicate step execution when an invocation crashes before reporting its result. Wrapping the API call in a task or step reduces repeated completed work; it does not remove the action-to-receipt gap. LangGraph task idempotency, Workflow duplicate steps
For transient failures, Workflow 4.8.8 defaults to three retries after the initial attempt; maxRetries, FatalError and RetryableError provide controls. Set a retry budget and delay that fit the dependency. Stopping retries does not establish whether an earlier request took effect. Workflow 4.8.8: errors and retrying
The same gap applies to the confirmation email. Give notification its own operation identity and delivery policy. A failed email must not cause the refund to be repeated.
Conceptual recovery: refund succeeded, receipt was lost
Preserve what approval and resume mean
Treat an approval as a decision about a specific proposal. In the refund design, store the approver, proposal version, action parameters and expiry. Accept a resume request only after checking its authorization and its match to the pending decision. A thread ID locates state; it is not an authorization policy.
A LangGraph interrupt resumes using the same thread_id and Command(resume=...). The interrupted node starts again from its beginning, so code before interrupt() runs again. Place proposal generation in a preceding saved node/task and keep the approval node narrow. Moving a side effect after the interrupt avoids repetition caused by that pause, but does not eliminate later crash retries. LangGraph interrupts
For the hypothetical refund, revalidate mutable eligibility after a long wait and before the first dispatch. If the amount or policy basis changes, create a revised proposal and obtain a decision on it. Once dispatch may have happened, resolve the original intent before replacing it; revalidation cannot erase an uncertain external outcome.
Version compatibility is also part of recovery. On Vercel, existing Workflow runs stay with their originating deployment, while new runs use newer deployments. A rerun on the latest deployment starts fresh with the inputs; treat it as a replacement run and retain the refund's business identity. Other Worlds require their own deployment strategy. Workflow versioning, Vercel World
For any runtime, record a state-schema version and decide whether old work will finish on retained code, pass through an explicit migration, or be replaced under the same business identity. Verify an old pending approval against the new deployment before retiring the old one. Keeping a record readable is only part of preserving its meaning.
Retain knowledge without turning it into proof
Use retrieval memory for information that helps later interactions, and keep operational decisions in structured records. A summary such as “customer was refunded” may help find a case; the provider receipt and business operation ID should determine whether that refund can be repeated.
LangGraph stores support data across threads and can support semantic search when configured. A store is not necessarily a vector database, and a vector search result is not an execution cursor. Begin with exact lookup if you already know the customer or case ID; add semantic retrieval when the problem is finding relevant prior information. LangGraph stores
Claude-Mem's published Claude Code architecture is an illustrative retrieval pipeline: hooks capture session information, a worker processes it, and stored observations or summaries can supply later context. This supports a knowledge-reuse example; it does not establish recovery of the observed application's pending actions. Scope that example to the documented integration: the source README at the 13.24.23 package revision also describes a Grok Bot path and Grok Mem branding. Check the selected host and release before adopting its setup. Claude Code architecture, 13.24.23 source README
For your own memory records, retain a source reference, subject/tenant scope, observation time and a way to correct or invalidate the fact. Read current order status from its authoritative system when it controls an action. Treat retrieved text as input to validate, rather than permission to operate.
Set retention separately for conversation history, reusable knowledge and operation receipts. LangGraph documents trimming, deletion and summarization as ways to manage conversation state. Those operations do not by themselves define a deletion policy for every historical checkpoint, store entry or external log. Memory management
For the refund design, keep operation records for the period in which your system accepts duplicate requests or replacements, subject to your data-retention requirements. If the provider's deduplication window expires sooner, make reconciliation the path for older ambiguous requests. Keeping fewer chat messages should not silently remove the evidence needed to resolve an unfinished action.
Choose the smallest design that meets the failure contract
Follow this sequence and stop adding infrastructure when the next requirement does not apply.
- Only a later interaction needs facts? Start with a persistent, scoped knowledge store and a retrieval policy. If restarting unfinished work is acceptable and repeats have no harmful effects, a durable execution runtime may be unnecessary.
- The same conversation or graph must continue? Use execution state with a stable thread identity. For a graph application, LangGraph's checkpointer and store can cover conversation continuity and cross-thread knowledge within one framework. Persistence
- Work must continue after the original request or worker disappears? Add or verify durable scheduling, saved execution results and a resume path. Choose LangGraph when its graph state and recovery model fit the application; consider Workflow when TypeScript workflow/step orchestration and the chosen World fit the deployment. These capabilities overlap. Functional API, Workflow 4.8.8 steps
- Any action can change an external system? Define business operation identities, duplicate-start handling, retry rules and uncertain-outcome reconciliation regardless of which runtime you choose.
- Both knowledge and execution must persist? Keep their ownership and retention explicit. Add a second runtime only for a requirement the first design does not meet, such as a distinct orchestration boundary; share business identities across the handoff.
Write the result as a short contract: what is stored; its identity and owner; where it survives; what wakes it; what can repeat; how an uncertain outcome is resolved. If any answer is missing, buying more storage has not yet completed the design.
Evidence scope: documentation checked on 13 September 2026 (Asia/Kolkata). Release anchors are LangGraph Python 1.2.11 and Workflow 4.8.8; hosted documentation can change independently. Workflow's World documentation explicitly distinguishes 4.x and 5.x behavior, so check the release and backend you deploy. The scenario and selection rules are design analysis, not measured reliability results. LangGraph release metadata, Workflow release metadata, World version scope
Verify the failures you promise to handle
Run these checks against the chosen package versions and deployment backend. Use a test provider or controlled substitute for external actions. These are proposed acceptance checks; they were not executed for this guide.
| Inject this condition | Evidence the design should produce |
|---|---|
| Start a new conversation for the same user, then a different tenant | Intended shared facts are retrievable in the first case; the second cannot access them. Thread state remains scoped correctly. |
| Replace the worker after a saved result | The new process loads the same operation and its saved result; pending work is delivered or explicitly recovered. |
| Kill the worker while a checkpoint is being written | Recovered progress matches the selected durability mode. Any lost result can be recomputed or reconciled safely. |
| Complete one parallel graph node and fail its peer | Recovery uses the successful node's saved pending writes when present; unfinished work follows the intended retry policy. |
| Complete a model step, pause, then resume | The saved proposal remains the one associated with approval. A deliberately fresh computation is identifiable as new work. |
| Approve after a restart, or submit a stale/duplicate approval | The correct pending operation accepts one applicable decision; stale proposals do not dispatch. |
| Have the provider act, then drop its reply or kill the worker | The operation enters an uncertain state, reuses its key/parameters, and converges on one provider outcome or a reconciliation path. |
| Submit the same business request concurrently and again after completion | Requests converge on one business operation and its result, including across separate run IDs. |
| Fail the notification after the refund succeeds | Only the notification is retried under its delivery policy; the refund receipt remains authoritative. |
| Exhaust retries, or exceed the provider's deduplication window | The operation stays visible with its outcome certainty and a named recovery owner; no fresh action is inferred from a timeout. |
| Resume old state after a deployment, then exercise the retention policy | Compatible code/schema can read the state, or an explicit migration/replacement handles it. Necessary pending-action evidence remains available. |
Capture the thread/run ID, business operation ID, checkpoint or event boundary, attempt records and provider receipt for each applicable check. A normal successful response alone does not prove crash recovery or duplicate-action protection.
The checkpoint, pending-write and task-retry checks follow the documented LangGraph boundaries; the duplicate-step and retry checks follow Workflow's documented behavior. The expected business outcomes are requirements you must implement and validate. LangGraph checkpointers, LangGraph task recovery, Workflow duplicate steps, Workflow 4.8.8 retry policy
Sources & further reading
Documentation informs the product behavior described here. The worked scenarios and conceptual diagrams explain how those behaviors fit together.
- Persistence ↗LangChain · Accessed 2026-09-13
- Memory ↗LangChain · Accessed 2026-09-13
- Checkpointers ↗LangChain · Accessed 2026-09-13
- Functional API overview ↗LangChain · Accessed 2026-09-13
- Interrupts ↗LangChain · Accessed 2026-09-13
- Stores ↗LangChain · Accessed 2026-09-13
- LangGraph 1.2.11 types.py ↗LangChain · Accessed 2026-09-13
- Workflows and Steps at Workflow 4.8.8 ↗Vercel · Accessed 2026-09-13
- Idempotency at Workflow 4.8.8 ↗Vercel · Accessed 2026-09-13
- Errors & Retrying at Workflow 4.8.8 ↗Vercel · Accessed 2026-09-13
- Local World ↗Vercel · Accessed 2026-09-13
- Vercel World ↗Vercel · Accessed 2026-09-13
- Step executed multiple times ↗Vercel · Accessed 2026-09-13
- Versioning ↗Vercel · Accessed 2026-09-13
- Architecture Overview: Claude Code integration ↗Claude-Mem · Accessed 2026-09-13
- README at claude-mem 13.24.23 source revision ↗thedotmack/claude-mem · Accessed 2026-09-13
- LangGraph 1.2.11 package metadata ↗PyPI / LangChain · Accessed 2026-09-13
- Workflow 4.8.8 package metadata ↗npm / Vercel · Accessed 2026-09-13