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 skipStreaming is 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

OptionPurpose
timelinesInclude list or exclude list
frameTypesSave only selected frame types
maxFramesKeep only the newest N frames per timeline
skipStreamingIgnore in-progress streaming frames

12.5 RestoreOptions

agent.restore(snapshot, {
  restorePointer: true,
  merge: false,
});

Full Option Set

OptionPurpose
restorePointerMove the Agent pointer to the saved pointer
mergeMerge 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.