# What Is the Snapshot Transcript Cache and How Does Session Restoration Work in Prime-Agent?

> Learn how the snapshot transcript cache in Prime-Agent enables session restoration for interrupted chats. Discover its hybrid memory/disk storage for seamless reconnection.

- Repository: [Prime Intellect/prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
- Tags: internals
- Published: 2026-08-12

---

**The snapshot transcript cache is a hybrid memory/disk storage component that buffers streamed session transcripts so Prime-Agent's daemon mode can restore interrupted chat sessions for reconnecting clients.**

The **snapshot transcript cache** enables reliable session restoration in Prime-Agent by storing a complete chat transcript while the daemon generates or delivers a session snapshot. This mechanism ensures clients can disconnect and reconnect without losing conversation context, picking up exactly where they left off. According to the Prime-Agent source code, the cache handles chunked streaming, automatic spill-to-disk, and reference-counted lifecycle management.

## How the Snapshot Transcript Cache Works

### Chunked Transcript Streaming

Rather than buffering entire transcripts in memory, Prime-Agent emits transcript data in **configurable chunks** (JSON-lines format). The `createSnapshotTranscriptChunks` generator in [`packages/coding-agent/src/modes/daemon/snapshot-transcript-cache.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/snapshot-transcript-cache.ts) constructs each chunk while respecting the `SNAPSHOT_TARGET_CHUNK_BYTES` limit (lines 27-70). This chunked approach prevents memory exhaustion when serializing large sessions.

### Hybrid Memory and File-Backed Storage

The cache dynamically selects storage based on total size:

- **In-memory mode**: While below `SNAPSHOT_MEMORY_CACHE_BYTES`, chunks stay in a `buffer` array in RAM (lines 56-73)
- **Spill-to-disk mode**: Once exceeded, the cache creates a private directory under `cacheRoot` and writes each chunk to separate `*.jsonl` files (lines 58-69)

This automatic switching ensures optimal performance for small snapshots while safely handling large transcripts.

### Reading Chunks Synchronously or Asynchronously

The cache provides two access patterns (lines 17-33, 76-90):

| Method | Behavior | Use Case |
|--------|----------|----------|
| `readChunk(index)` | Returns chunk immediately | Client already knows chunk exists |
| `waitForChunk(index)` | Returns `Promise` that resolves when chunk available | Snapshot still being generated |

The `waitForChunk` method is essential for **catch-up scenarios** where a client connects while the daemon is still streaming the snapshot.

### Reference-Counted Lifecycle Management

Consumers control cache lifetime through explicit reference counting (lines 93-107):

```typescript
const release = cache.retain();  // increment reader count
// ... read chunks ...
release();                       // decrement count, may trigger disposal

```

The cache only disposes when:
1. `dispose()` has been explicitly called, **and**
2. All readers have released their handles

### Completion and Failure States

The cache exposes explicit state transitions (lines 44-62, 16-24):

- `markComplete()` — signals finished snapshot, resolves pending `waitForChunk` calls with `undefined`
- `markFailed(error)` — aborts snapshot, rejects all pending waiters
- `dispose()` — removes temporary directory, clears memory structures, and deregisters from daemon's `transcriptCaches` map

## How Session Restoration Works in Prime-Agent

### Step 1: Snapshot Creation

When a client requests a session snapshot, the daemon streams the transcript using `createSnapshotTranscriptChunks` and feeds chunks into a fresh `SnapshotTranscriptCache` instance via `appendEncodedChunk`. The test file [`4677-snapshot-catchup-replacement.test.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/4677-snapshot-catchup-replacement.test.ts) demonstrates this complete flow, including chunk generation and cache population.

### Step 2: Cache Registration

The daemon maintains a `transcriptCaches` map keyed by **active session ID** (lines 14-20). Each entry stores:
- The `snapshotId`
- Chunk data (memory or disk-backed)
- Completion status

This registry allows the daemon to locate snapshots for reconnecting clients.

### Step 3: Client Attachment

A reconnecting client supplies its stored `snapshotId`. The daemon:
1. Looks up the corresponding `SnapshotTranscriptCache`
2. Calls `retain()` to prevent premature disposal
3. Begins reading chunks via `readChunk` or `waitForChunk`

### Step 4: Session Rehydration

As chunks arrive, the client deserializes each message:

```typescript
const release = cache.retain();

for (let i = 0; i < cache.chunkCount; i++) {
  const data = await cache.waitForChunk(i);
  if (!data) break;  // snapshot complete
  
  const { messages } = JSON.parse(data.toString());
  // Rebuild session message list...
}

release();

```

Once the cache reports `complete` (or the final `session_snapshot_end` event arrives), the client resumes normal interaction.

### Step 5: Cleanup

After full restoration, the client releases its retain handle. The daemon calls `dispose()` on the cache; if no other readers remain, the temporary directory is removed and memory structures are cleared (lines 9-15, 20-28).

## Complete Code Example

```typescript
import { SnapshotTranscriptCache } from './snapshot-transcript-cache';
import { createSnapshotTranscriptChunks } from './create-snapshot';

// Daemon: Create and populate cache during snapshot generation
const cache = new SnapshotTranscriptCache({
  activeSessionId: "session-123",
  snapshotId: "snap-001",
  cacheRoot: "/tmp/prime-agent-snapshots",
});

// Stream chunks as they become available
for (const chunk of createSnapshotTranscriptChunks({
  activeSessionId: "session-123",
  snapshotId: "snap-001",
  messages: recentMessages,
})) {
  cache.appendEncodedChunk(chunk);
}
cache.markComplete();

// Client: Restore session from cache
const restoreSession = async (cache: SnapshotTranscriptCache) => {
  const release = cache.retain();
  const restoredMessages: any[] = [];
  
  try {
    for (let i = 0; ; i++) {
      const data = await cache.waitForChunk(i);
      if (!data) break;
      
      const { messages } = JSON.parse(data.toString());
      restoredMessages.push(...messages);
    }
    return restoredMessages;
  } finally {
    release();
  }
};

```

## Key Source Files

- **[`packages/coding-agent/src/modes/daemon/snapshot-transcript-cache.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/snapshot-transcript-cache.ts)** — Core cache implementation with chunked storage, I/O handling, and lifecycle management
- **[`packages/coding-agent/test/suite/regressions/4677-snapshot-catchup-replacement.test.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/test/suite/regressions/4677-snapshot-catchup-replacement.test.ts)** — Regression test demonstrating snapshot generation and replacement logic
- **[`packages/coding-agent/src/modes/daemon/daemon-client.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/daemon-client.ts)** — Client attachment logic for session restoration
- **[`packages/coding-agent/src/modes/daemon/create-snapshot.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/create-snapshot.ts)** — Entry point orchestrating `createSnapshotTranscriptChunks` and cache writes

## Summary

- The **snapshot transcript cache** provides hybrid memory/disk storage for streamed session transcripts in Prime-Agent's daemon mode
- **Chunked streaming** via `createSnapshotTranscriptChunks` prevents memory issues with large transcripts
- **Automatic spill-to-disk** activates when `SNAPSHOT_MEMORY_CACHE_BYTES` is exceeded
- **Reference counting** ensures caches survive while any client is reading, then clean up automatically
- **Session restoration** works by: creating snapshot → registering cache → client attachment → chunk rehydration → cleanup
- The `waitForChunk` method enables **catch-up streaming** where clients connect during active snapshot generation

## Frequently Asked Questions

### What triggers the cache to switch from memory to disk storage?

The cache monitors total buffered size against `SNAPSHOT_MEMORY_CACHE_BYTES`. Once appended chunks exceed this threshold, the cache creates a private directory under `cacheRoot` and begins writing each new chunk to individual `*.jsonl` files (lines 58-69). Existing memory chunks remain in RAM; only new data spills to disk.

### How does the cache handle multiple clients reading the same snapshot?

Each client calls `retain()` to increment an internal reader counter before reading. The cache only disposes when `dispose()` was requested **and** the reader count reaches zero. This prevents premature cleanup while any client is still restoring the session, even if the original snapshot generation has completed.

### What happens if snapshot generation fails midway?

Calling `markFailed(error)` immediately rejects all pending `waitForChunk` promises with the provided error. Clients receive the failure and can handle reconnection or error recovery. The cache remains accessible until all readers release it, allowing partial data retrieval if needed before disposal.

### Can clients read chunks that were written to disk as fast as memory chunks?

Yes. The `readChunk` and `waitForChunk` methods abstract the storage location. Synchronous reads from disk incur filesystem latency, but the API presents uniform behavior regardless of whether the chunk resides in the `buffer` array or a `*.jsonl` file in the temporary directory.