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

> Discover how mksglu/context-mode indexes and searches session events using SQLite and FTS5. Learn about its dual-storage architecture for resume functionality and event retrieval.

- Repository: [Mert Köseoğlu/context-mode](https://github.com/mksglu/context-mode)
- Tags: how-to-guide
- Published: 2026-04-24

---

**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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/src/adapters/opencode/index.ts) (line 274) generates these files, appending event data as markdown sections:

```markdown

## 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`](https://github.com/mksglu/context-mode/blob/main/src/server.ts) (lines 99-103), this function scans the sessions directory for `*-events.md` files and processes them through the ContentStore:

```typescript
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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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:

```xml
<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`](https://github.com/mksglu/context-mode/blob/main/src/session/db.ts)). The [`pi-extension.ts`](https://github.com/mksglu/context-mode/blob/main/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.

## Searching Indexed Events with ctx_search

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`](https://github.com/mksglu/context-mode/blob/main/src/server.ts) around line 1180, the tool accepts queries and optional source filtering:

```typescript
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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/src/session/db.ts) and platform-specific adapters.
- Automatic indexing occurs via `maybeIndexSessionEvents` in [`src/server.ts`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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`](https://github.com/mksglu/context-mode/blob/main/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.