Skip to main content

Hook Lifecycle

Claude-Mem implements a 5-stage hook system that captures development work across Claude Code sessions. This document provides a complete technical reference for developers implementing this pattern on other platforms.

Architecture Overview

System Architecture

This two-process architecture works in both Claude Code and VS Code: Key Principles:
  • Extension process never blocks (fire-and-forget HTTP)
  • Worker processes observations asynchronously
  • Session state persists across IDE restarts

VS Code Extension API Integration Points

For developers porting to VS Code, here’s where to hook into the VS Code Extension API: Implementation Examples:

Async Processing Pipeline

How observations flow from extension to database without blocking the IDE: Critical Pattern: The extension’s HTTP call has a 2-second timeout and doesn’t wait for AI processing. The worker handles compression asynchronously using an event-driven queue.

The 5 Lifecycle Stages

Hook Configuration

Hooks are configured in plugin/hooks/hooks.json:

Stage 1: SessionStart

Timing: When user opens Claude Code or resumes session Hooks Triggered (in order):
  1. worker-service.cjs start - Starts the worker service
  2. context-hook.js - Fetches and silently injects prior session context
(Runtime setup is handled out-of-band by npx claude-mem install / npx claude-mem repair. The Setup phase runs a sub-100ms version-check.js that prompts the user to repair if the .install-version marker is stale.)
As of Claude Code 2.1.0 (ultrathink update), SessionStart hooks no longer display user-visible messages. Context is silently injected via hookSpecificOutput.additionalContext.

Sequence Diagram

Context Hook (context-hook.js)

Purpose: Inject context from previous sessions into Claude’s initial context. Input (via stdin):
Processing:
  1. Wait for worker to be available (health check, max 10 seconds)
  2. Call: GET http://127.0.0.1:<worker-port>/api/context/inject?project={project}
  3. Return formatted context as additionalContext in hookSpecificOutput
Output (via stdout):
Implementation: src/hooks/context-hook.ts

Stage 2: UserPromptSubmit

Timing: When user submits any prompt in a session Hook: new-hook.js

Sequence Diagram

Key Pattern: The INSERT OR IGNORE ensures the same session_id always maps to the same sessionDbId, enabling conversation continuations. Input (via stdin):
Processing Steps:
Output:
Implementation: src/hooks/new-hook.ts
The same session_id flows through ALL hooks in a conversation. The createSDKSession call is idempotent - it returns the existing session for continuation prompts.

Stage 3: PostToolUse

Timing: After Claude uses any tool (Read, Bash, Grep, Write, etc.) Hook: save-hook.js

Sequence Diagram

Key Pattern: The hook returns immediately after HTTP POST. AI compression happens asynchronously in the worker without blocking Claude’s tool execution. Input (via stdin):
Processing Steps:
Worker Processing:
  1. Looks up or creates session: createSDKSession(claudeSessionId, '', '')
  2. Gets prompt counter
  3. Checks privacy (skips if user prompt was entirely private)
  4. Strips memory tags from tool_input and tool_response
  5. Queues observation for SDK agent processing
  6. SDK agent calls Claude to compress into structured observation
  7. Stores observation in database and syncs to Chroma
Output:
Implementation: src/hooks/save-hook.ts

Stage 4: Stop

Timing: When user stops or pauses asking questions Hook: summary-hook.js

Sequence Diagram

Key Pattern: The summary is generated asynchronously and doesn’t block the user from resuming work or closing the session. Input (via stdin):
Processing Steps:
Worker Processing:
  1. Queues summarization for SDK agent
  2. Agent calls Claude to generate structured summary
  3. Summary stored in database with fields: request, investigated, learned, completed, next_steps
Output:
Implementation: src/hooks/summary-hook.ts

Stage 5: SessionEnd

Timing: When Claude Code session closes (exit, clear, logout, etc.) Hook: cleanup-hook.js

Sequence Diagram

Key Pattern: Session completion is tracked for analytics and UI updates, but doesn’t prevent the user from closing the IDE. Input (via stdin):
Processing Steps:
Worker Processing:
  1. Finds session by claudeSessionId
  2. Marks session as ‘completed’ in database
  3. Broadcasts session completion event to SSE clients
Output:
Implementation: src/hooks/cleanup-hook.ts

Session State Machine

Understanding session lifecycle and state transitions: Key Insights:
  • session_id never changes during a conversation
  • sessionDbId is the database primary key for the session
  • promptNumber increments with each user prompt
  • State transitions are non-blocking (fire-and-forget pattern)

Database Schema

The session-centric data model that enables cross-session memory: Idempotency Pattern:
Foreign Key Cascade: All child tables (user_prompts, observations, session_summaries) use session_id foreign key referencing SDK_SESSIONS.id. This ensures:
  • All data for a session is queryable by sessionDbId
  • Session deletions cascade to child tables
  • Efficient joins for context injection
Never generate your own session IDs. Always use the session_id provided by the IDE - this is the source of truth for linking all data together.

Privacy & Tag Stripping

Dual-Tag System

Processing Pipeline

Location: src/utils/tag-stripping.ts
Execution Order (Edge Processing):
  1. new-hook.js strips tags from user prompt before saving
  2. save-hook.js strips tags from tool data before sending to worker
  3. Worker strips tags again (defense in depth) before storing

SDK Agent Processing

Query Loop (Event-Driven)

Location: src/services/worker/SDKAgent.ts

Message Types

The message generator yields three types of prompts:
  1. Initial Prompt (prompt #1): Full instructions for starting observation
  2. Continuation Prompt (prompt #2+): Context-only for continuing work
  3. Observation Prompts: Tool use data to compress into observations
  4. Summary Prompts: Session data to summarize

Implementation Checklist

For developers implementing this pattern on other platforms:

Hook Registration

  • Define hook entry points in platform config
  • 5 hook types: SessionStart (2 hooks), UserPromptSubmit, PostToolUse, Stop, SessionEnd
  • Pass session_id, cwd, and context-specific data

Database Schema

  • SQLite with WAL mode
  • 4 main tables: sdk_sessions, user_prompts, observations, session_summaries
  • Indices for common queries

Worker Service

  • HTTP server on configured worker port
  • Bun runtime for process management
  • 3 core services: SessionManager, SDKAgent, DatabaseManager

Hook Implementation

  • context-hook: GET /api/context/inject (with health check)
  • new-hook: createSDKSession, saveUserPrompt, POST /sessions/{id}/init
  • save-hook: Skip low-value tools, POST /api/sessions/observations
  • summary-hook: Parse transcript, POST /api/sessions/summarize
  • cleanup-hook: POST /api/sessions/complete

Privacy & Tags

  • Implement stripMemoryTags()
  • Process tags at hook layer (edge processing)
  • Max tag count = 100 (ReDoS protection)

SDK Integration

  • Call Claude Agent SDK to process observations/summaries
  • Parse XML responses for structured data
  • Store to database + sync to vector DB

Key Design Principles

  1. Session ID is Source of Truth: Never generate your own session IDs
  2. Idempotent Database Operations: Use INSERT OR IGNORE for session creation
  3. Edge Processing for Privacy: Strip tags at hook layer before data reaches worker
  4. Fire-and-Forget for Non-Blocking: HTTP timeouts prevent IDE blocking
  5. Event-Driven, Not Polling: Zero-latency queue notification to SDK agent
  6. Everything Saves Always: No “orphaned” sessions

Common Pitfalls