How context-mode Indexes and Searches Session Events for Resume Functionality

context-mode implements a dual-storage architecture that persists hook-generated events to SQLite tables while simultaneously indexing markdown dumps via FTS5, enabling automatic resume snapshot generation and on-demand retrieval through the ctx_search tool.

The mksglu/context-mode repository provides a session management system designed to maintain context across long-running AI coding sessions without exhausting token limits. By combining structured database storage with full-text search capabilities, the system captures every hook event into durable storage and searchable indexes. This article examines the specific mechanisms—including database schemas, FTS5 indexing, and snapshot generation—that power the resume functionality.

Dual-Storage Architecture

The system employs two complementary persistence layers to balance structured data integrity with searchability.

SQLite Session Tables

Raw events are stored in the session_events table defined in src/session/db.ts. This table maintains a persistent per-project log capturing event types, categories, timestamps, and data payloads. The SessionDB class provides the primary interface through methods including insertEvent, getEvents, upsertResume, getResume, and markResumeConsumed.

FTS5 ContentStore

Simultaneously, events are indexed in an FTS5 SQLite database managed by the ContentStore class in src/store.ts. This full-text search index stores parsed markdown chunks from session events under the source identifier "session-events", enabling BM25-ranked queries. The database resides at ~/.claude/context-mode/content/<hash>.db and persists across tool invocations.

Persisting Hook Events

When platform hooks generate events, the system writes data through two parallel paths to ensure both durability and indexability.

Database Insertion

The executor calls db.insertEvent(sessionId, event, sourceHook) (implemented in src/session/db.ts lines 10-44), which writes rows to session_events and updates session metadata in the session_meta table.

Markdown File Generation

Each platform adapter implements getSessionEventsPath() to return a filesystem path following the pattern:


${hash}${worktreeSuffix}-events.md

For example, the OpenCode adapter in src/adapters/opencode/index.ts (line 274) generates these files, appending event data as markdown sections:


## file_write

/path/to/file.ts

Automatic FTS5 Indexing

The server periodically processes accumulated markdown files to populate the search index.

The maybeIndexSessionEvents Function

Located in src/server.ts (lines 99-103), this function scans the sessions directory for *-events.md files and processes them through the ContentStore:

function maybeIndexSessionEvents(store: ContentStore): void {
  const sessionsDir = getSessionDir();
  const files = readdirSync(sessionsDir)
                 .filter(f => f.endsWith("-events.md"));
  for (const file of files) {
    const filePath = join(sessionsDir, file);
    store.index({ path: filePath, source: "session-events" });
    unlinkSync(filePath); // Delete after indexing
  }
}

ContentStore Processing

The store.index method (line 215 in src/store.ts) parses markdown into semantic chunks and inserts them into the FTS5 content table. This operation runs automatically on every server request, ensuring the search index remains current while removing ephemeral markdown files to prevent duplication.

Building Resume Snapshots

Before session compaction or fresh starts, the system generates concise XML summaries that embed hooks for detailed retrieval.

Snapshot Generation Logic

The buildResumeSnapshot function in src/session/snapshot.ts processes all stored events from SessionDB.getEvents, grouping them by category (files, errors, tasks). For each group, it generates XML containing summary statistics and auto-generated ctx_search calls:

<files count="12">
    foo.ts (write×3, read×2)
    ctx_search(
      queries: ["foo.ts write", "foo.ts read"],
      source: "session-events"
    )
</files>

Database Persistence

The snapshot is persisted via db.upsertResume(sessionId, snapshot, eventCount) (lines 13-15 in src/session/db.ts). The pi-extension.ts component retrieves this via db.getResume (line 275), injects the XML into the system prompt, and marks it consumed with markResumeConsumed to prevent duplicate injection.

The ctx_search tool provides on-demand access to the indexed event history without loading complete session logs into context.

Tool Registration

Registered in src/server.ts around line 1180, the tool accepts queries and optional source filtering:

server.registerTool(
  "ctx_search",
  {
    inputSchema: z.object({
      queries: z.array(z.string()),
      source: z.string().optional(),
    })
  },
  async ({ queries, source }) => {
    const results = await store.search(queries, { source });
    return trackResponse("ctx_search", { content: results });
  }
);

Search Implementation

The store.search method (line 246 in src/store.ts) executes FTS5 queries against the content table. When source: "session-events" is specified, the search restricts results to indexed session history, allowing the model to retrieve original event text on demand rather than maintaining full histories in the active context window.

Complete Resume Workflow

The end-to-end process operates across five distinct phases:

  1. Event Capture: Hooks trigger insertEvent, simultaneously writing structured data to SQLite and markdown sections to ${hash}-events.md files.
  2. Background Indexing: The server executes maybeIndexSessionEvents on every request, feeding markdown content into the FTS5-backed ContentStore and deleting source files.
  3. Snapshot Injection: Before processing new batches, pi-extension.ts queries getResume and injects existing XML snapshots into the system prompt, immediately marking them consumed via markResumeConsumed.
  4. Compaction: When sessions exceed configured event limits, the server invokes buildResumeSnapshot, stores the result via upsertResume, and truncates old events from session_events.
  5. Detail Retrieval: During conversation, the model executes ctx_search with source: "session-events" to pull specific historical details referenced in the compact snapshot.

Summary

  • context-mode maintains dual storage: SQLite tables for structured data (session_events, session_resume) and FTS5 indexes for full-text search via ContentStore.
  • Events are written to both database tables and ${hash}${worktreeSuffix}-events.md files by src/session/db.ts and platform-specific adapters.
  • Automatic indexing occurs via maybeIndexSessionEvents in src/server.ts, which populates the FTS5 content table and cleans up ephemeral markdown files.
  • Resume snapshots are XML documents generated by buildResumeSnapshot in src/session/snapshot.ts, embedding executable ctx_search calls for granular detail retrieval.
  • The ctx_search tool queries indexed content through store.search in src/store.ts, enabling models to access specific historical events without reloading complete session histories.

Frequently Asked Questions

How does context-mode prevent duplicate resume snapshots from being injected?

The system tracks consumption status through the consumed boolean field in the session_resume table. When pi-extension.ts retrieves a resume via db.getResume, it checks this flag; if false, it injects the snapshot into the prompt and immediately calls markResumeConsumed to update the database record, ensuring the snapshot appears only once in the conversation history.

Can I search session events from specific categories only?

While the ctx_search tool accepts a source parameter to restrict searches to "session-events", category-specific filtering primarily occurs during snapshot generation in src/session/snapshot.ts. The buildResumeSnapshot function groups events by category (files, errors, tasks) when constructing the XML summary, though the underlying FTS5 index stores the raw markdown content without explicit category tags for direct querying.

What happens to the markdown files after indexing?

The maybeIndexSessionEvents function in src/server.ts deletes source markdown files immediately after successful indexing via unlinkSync(filePath). This cleanup prevents duplicate indexing on subsequent requests while the content remains permanently searchable in the FTS5 database stored within the ContentStore file at ~/.claude/context-mode/content/<hash>.db.

Where is the resume snapshot stored between sessions?

Resume snapshots persist in the session_resume table managed by src/session/db.ts. The upsertResume method stores the XML snapshot string alongside metadata including event counts and timestamps, while getResume retrieves it using the session ID, enabling cross-request persistence within the project's SQLite database located in the context-mode configuration directory.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →