A3S Docs
A3S Code

Persistence

Saving and resuming sessions

Persistence

Persistence lets a session survive process restarts and gives product surfaces a stable session ID.

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'),
});

Memory And Sessions

Session persistence stores conversation state. 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.

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.

On this page