Persistence
Saving and resuming sessions
Persistence
Persistence lets a session survive process restarts and gives product surfaces a stable session ID.
A3S Code persists three related but different things:
| Object | Written by | Resumed by | Purpose |
|---|---|---|---|
| Session snapshot | session.save() or autoSave | agent.resumeSession(id, options) | Rehydrate a conversation plus runtime evidence such as artifacts, traces, run records, verification reports, and subagent task snapshots. |
| Loop checkpoint | Agent loop while a run is in progress | session.resumeRun(runId) | Continue an interrupted run from the last completed tool-round boundary. Completed in-process runs delete this checkpoint. |
| Workflow checkpoint | parallelResumable / workflow phases | parallelResumable(specs, workflowId) | Skip already-completed orchestration steps after a process restart. |
File Session Store
import { FileSessionStore } from '@a3s-lab/code';
const session = agent.session('/repo', {
sessionId: 'release-review',
sessionStore: new FileSessionStore('./.a3s/sessions'),
autoSave: true,
});
await session.send('Review release readiness');
await session.save();Resume
const resumed = agent.resumeSession('release-review', {
sessionStore: new FileSessionStore('./.a3s/sessions'),
});resumeSession restores a saved session snapshot. It is not the same as
resumeRun: use resumeSession when the user is continuing a saved
conversation, and use resumeRun(runId) only when a run checkpoint exists for
an interrupted run.
Memory And Sessions
Session persistence stores conversation and replay evidence. Memory stores reusable task facts. Use both when you want resumable workflows that also learn from repeated tasks.
Loop Checkpoints and Run Resumption
When a SessionStore is configured, the agent loop persists a LoopCheckpoint
after each completed tool round. The boundary policy is strict: checkpoints are
taken only between tool rounds, never mid-tool. If a process dies while a
tool is executing, that round's work is lost on resume and the LLM
re-deliberates from the previous checkpoint — re-running a non-idempotent tool
(write, bash) on the wrong side of the boundary is worse than re-asking the LLM.
session.resumeRun(runId) (Node) / session.resume_run(run_id) (Python) — core
AgentSession::resume_run(checkpoint_run_id) — loads the latest checkpoint
stored under that run ID and replays the loop from the last boundary. Because
the checkpoint lives in the shared store, resume can happen on any node that
shares it. Cumulative accounting continues rather than restarting at zero:
total_usage and tool_calls_count carry forward from the checkpoint. A new run
ID is allocated for the resumed work; the old-to-new relationship is host
metadata, not interpreted by the framework.
Completed runs are not resumed through resumeRun; their final state is
available through runs(), runEvents(runId), artifacts, verification reports,
and session snapshots.
const result = await session.resumeRun('run-abc123');
console.log(result.totalTokens);result = session.resume_run('run-abc123')
print(result.total_tokens)resume_run rejects when the session has no sessionStore configured (or when
no checkpoint exists for the given ID). SessionStore gains
save_loop_checkpoint / load_loop_checkpoint / delete_loop_checkpoint; the
file store's writes are crash-atomic. LoopCheckpoint::ensure_loadable() is
called right after deserialization and rejects checkpoints from a future,
incompatible schema version, so neither resume_run nor the live-run sink acts
on an unreadable checkpoint.
See CHANGELOG [3.3.0] — "Loop checkpoints + run resumption" — and [3.4.0]
"LoopCheckpoint::ensure_loadable()".
Workflow Checkpoints
WorkflowCheckpoint is the step-boundary analogue of the tool-round
LoopCheckpoint, one level up: it journals completed orchestration steps so an
interrupted workflow resumes from the longest completed prefix. Its fields are
schema_version, workflow_id, steps, and checkpoint_ms, with the schema
pinned by the WORKFLOW_CHECKPOINT_SCHEMA_VERSION constant. A resuming run skips
the recorded steps and re-dispatches only the rest.
SessionStore gains save_workflow_checkpoint / load_workflow_checkpoint /
delete_workflow_checkpoint (default no-ops; the file store writes
crash-atomically). Loads from a future, incompatible schema version are rejected
via WorkflowCheckpoint::ensure_loadable().
This pairs with the orchestration grammar — see Orchestration and Multi-Machine.
See CHANGELOG [3.4.0] — "WorkflowCheckpoint".
Resuming on a Different Node
Both checkpoint types are serializable. Combined with a shared SessionStore
and a pluggable executor, this lets a host resume an interrupted run or workflow
on a different node from the one that started it — the framework owns the
serializable contract, the host owns placement and transport.
Operational Notes
Keep session stores out of public commits when they may contain prompts, tool output, or private file paths.