How Session Continuity Works Across Conversation Compaction in Claude Code with context-mode
Context-mode preserves complete session history across automatic conversation compactions by recording every tool execution to a SQLite database, generating a compact XML resume snapshot before truncation, and re-injecting that snapshot as a system directive after the compact.
The context-mode repository (mksglu/context-mode) solves a critical limitation in Claude Code: the loss of historical context when conversations automatically compact to stay within token limits. This open-source tool ensures session continuity across conversation compaction by intercepting tool calls at three specific lifecycle phases and resurrecting previous context through a rigorous persistence pipeline.
The Three-Pillar Continuity Architecture
Context-mode maintains state through three tightly-coupled lifecycle hooks that execute around compaction events. Together, they create an immutable audit trail that survives unlimited conversation truncations.
PostToolUse Hook: Capturing Every Action
Immediately after each tool execution, the PostToolUse hook (implemented in hooks/posttooluse.mjs) extracts structured events and writes them to a per-project SQLite database named session.db.
// hooks/posttooluse.mjs
const { extractEvents } = await loadExtract();
const db = new SessionDB({ dbPath });
const sessionId = getSessionId(input);
// ensure meta row exists
db.ensureSession(sessionId, process.env.CLAUDE_PROJECT_DIR || process.cwd());
// turn a tool call into one or more SessionEvent objects
const events = extractEvents({
tool_name,
tool_input,
tool_response,
tool_output
});
// write each event atomically (deduplication + FIFO eviction)
for (const ev of events) {
db.insertEvent(sessionId, ev, "PostToolUse");
}
The extractEvents function (located in src/session/extract.ts) classifies tool calls into 13 distinct categories (file operations, git commands, environment changes, etc.) and normalizes them into SessionEvent objects. The SessionDB.insertEvent method (in src/session/db.ts) provides atomic storage with built-in deduplication and FIFO eviction once the per-session limit of MAX_EVENTS_PER_SESSION = 1000 events is reached.
PreCompact Hook: Building the Resume Snapshot
Right before Claude truncates the conversation to manage token limits, the PreCompact hook (hooks/precompact.mjs) generates a compact-size XML resume snapshot that encodes the session's essential context without the bloat.
// precompact.mjs
const events = db.getEvents(sessionId);
if (events.length) {
const stats = db.getSessionStats(sessionId);
const snapshot = buildResumeSnapshot(events, {
compactCount: (stats?.compact_count ?? 0) + 1,
});
db.upsertResume(sessionId, snapshot, events.length);
db.incrementCompactCount(sessionId);
}
The buildResumeSnapshot function (in src/session/snapshot.ts) groups events by category, generates concise XML summaries for each group, and appends a search tool call (ctx_search) that can retrieve full details on demand. Despite encoding a complete table of contents for the session, the snapshot remains under 2 KB, well within Claude's token budget for system context.
SessionStart Hook: Restoring Lost Context
When Claude restarts after a compaction event, the SessionStart hook (hooks/sessionstart.mjs) detects the source === "compact" condition and strategically re-injects the stored snapshot as a system-level directive.
// sessionstart.mjs – compact branch
if (source === "compact") {
const resume = db.getResume(sessionId);
if (resume && !resume.consumed) db.markResumeConsumed(sessionId);
const events = getSessionEvents(db, sessionId);
if (events.length) {
const eventMeta = writeSessionEventsFile(
events,
getSessionEventsPath()
);
additionalContext += buildSessionDirective(
"compact",
eventMeta,
toolNamer
);
}
}
The getResume function retrieves the XML snapshot, while markResumeConsumed prevents duplicate injection. The buildSessionDirective function wraps the snapshot in a <session_resume …> XML block that Claude treats as immutable system context, effectively resurrecting the knowledge that would otherwise have been lost to truncation.
Full-History Resume with --continue
When users restart a session using the --continue flag, context-mode shifts from "snapshot mode" to "full replay mode." The SessionStart hook detects source === "resume" and executes a complete context restoration:
- Clears the cleanup flag to prevent old session data from being purged
- Retrieves all events that survived previous compactions via
getLatestSessionEvents - Writes raw events to
session_events.jsonfor auto-indexing - Injects both the compact snapshot and the full event log via
buildSessionDirective("resume", …)
This dual-injection strategy allows the LLM to reconstruct the exact pre-compact state by combining the categorized snapshot with granular event details.
Analytics and Continuity Metrics
The system tracks continuity health through src/session/analytics.ts, which aggregates metrics including total_events, compact_count, and per-category breakdowns. These statistics power the Insight UI and benchmark reports, while the snapshot header includes compact_count to generate human-readable session footers:
Session continuity: 25 events preserved across 2 compactions
Summary
- Event Capture: Every tool call is immediately persisted to
session.dbvia the PostToolUse hook, with automatic deduplication and FIFO eviction at 1000 events per session. - Snapshot Generation: The PreCompact hook condenses full history into a <2KB XML resume snapshot containing categorized summaries and searchable references to full details.
- Context Restoration: The SessionStart hook automatically re-injects the resume snapshot after compaction, while
--continuemode provides full event replay for complete state reconstruction. - Storage Backend: All persistence uses atomic SQLite operations in
src/session/db.ts, ensuring durability even during abrupt session termination.
Frequently Asked Questions
How large are the resume snapshots?
Resume snapshots are intentionally compressed to under 2 KB regardless of session length. The buildResumeSnapshot function in src/session/snapshot.ts achieves this by categorizing events and referencing full details through a ctx_search tool call rather than inlining verbose content, keeping the payload well within Claude's system context budget.
What happens if a session compacts multiple times?
The system maintains continuity across unlimited compactions through the compact_count counter stored in session.db. Each PreCompact execution increments this counter and generates a new resume snapshot that incorporates all previous events. The FIFO eviction policy in SessionDB.insertEvent ensures the most recent 1000 events are always available for snapshot generation.
Can I inspect the session database manually?
Yes. The session.db file is a standard SQLite database located in your project directory. You can query it directly using the SQLite CLI or any database browser to inspect the events table, session_resume table, and metadata fields including event_count, compact_count, and last_event_at.
Does context-mode work with any Claude Code project?
Context-mode automatically activates for any project where the hooks are installed. It determines the project root via process.env.CLAUDE_PROJECT_DIR or process.cwd(), creating isolated session.db files per project. This ensures session continuity is scoped correctly when working across multiple codebases.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →