Chapter 12: Snapshot and Persistence
Snapshots let you save and restore an Agent's timeline state. This is useful for local drafts, game saves, chat sessions, debugging, and server-side persistence.
12.1 Save and Restore in Two Lines
const snapshot = agent.snapshot();
localStorage.setItem('session', JSON.stringify(snapshot));
Restore later:
const raw = localStorage.getItem('session');
if (raw) agent.restore(JSON.parse(raw));
Call restore() after features are registered and initialized, before new writes happen.
12.2 Snapshot Shape
A snapshot is plain JSON-serializable data.
interface AgentSnapshot {
version: number;
pointer: number;
timelines: SnapshotTimeline[];
}
interface SnapshotTimeline {
name: string;
frames: SnapshotFrame[];
}
Because it is plain data, you can store it in localStorage, IndexedDB, files, or a database.
12.3 Automatic Exclusion Rules
By default, ChronoAI skips timelines that should not be persisted:
- timelines with
retain: 0 - dynamic prompt timelines, because they can be recomputed
- timelines marked
persist: false - streaming frames when
skipStreamingis enabled
You can override persistence behavior in the timeline definition.
useTimeline({ name: 'api-key', persist: false });
useTimeline({ name: 'session-flags', retain: 0, persist: true });
12.4 SnapshotOptions
Use options to control what gets saved.
agent.snapshot({
timelines: ['user-input', 'content-body'],
maxFrames: 20,
skipStreaming: true,
});
Full Option Set
| Option | Purpose |
|---|---|
timelines | Include list or exclude list |
frameTypes | Save only selected frame types |
maxFrames | Keep only the newest N frames per timeline |
skipStreaming | Ignore in-progress streaming frames |
12.5 RestoreOptions
agent.restore(snapshot, {
restorePointer: true,
merge: false,
});
Full Option Set
| Option | Purpose |
|---|---|
restorePointer | Move the Agent pointer to the saved pointer |
merge | Merge frames into existing state instead of clearing first |
Use merge: true when loading partial state into an existing session.
12.6 Practice: Add Save Slots to Roleplay
Directory Structure
src/
main.ts
agent.ts
+ persist.ts
Step 1: Create persist.ts
import type { Agent, AgentSnapshot } from 'chronoai';
const KEY = 'roleplay-save';
export function saveAgent(agent: Agent) {
const snapshot = agent.snapshot({
maxFrames: 50,
skipStreaming: true,
});
localStorage.setItem(KEY, JSON.stringify(snapshot));
}
export function restoreAgent(agent: Agent) {
const raw = localStorage.getItem(KEY);
if (!raw) return false;
const snapshot = JSON.parse(raw) as AgentSnapshot;
agent.restore(snapshot);
return true;
}
Step 2: Connect main.ts
const agent = createRoleplayAgent();
agent.initialize();
restoreAgent(agent);
saveButton.addEventListener('click', () => saveAgent(agent));
You can also save automatically after each successful request.
agent.observeTimeline('dialogue', () => saveAgent(agent));
Result
The app can reload and continue from the previous timeline state. User messages, assistant replies, status data, and the current pointer can all be restored.
12.7 Server-side Persistence
On Node.js, snapshots can be stored as JSON files or database records.
import fs from 'node:fs/promises';
export async function saveToFile(agent: Agent, file: string) {
await fs.writeFile(file, JSON.stringify(agent.snapshot(), null, 2));
}
export async function restoreFromFile(agent: Agent, file: string) {
const raw = await fs.readFile(file, 'utf8');
agent.restore(JSON.parse(raw));
}
For production systems, store snapshots per user, session, or branch id.
Summary
snapshot()serializes timeline state.restore()loads it back into an initialized Agent.- Persistence can be local or server-side.
- Options let you control timelines, frame types, frame counts, and pointer behavior.
You now have the full ChronoAI quick-start path: timelines, derivation, commands, features, prompts, streaming, rendering, and persistence.