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
| Stage | Hook | Trigger | Purpose |
|---|---|---|---|
| 1. SessionStart | context-hook.js | User opens Claude Code | Inject prior context silently |
| 2. UserPromptSubmit | new-hook.js | User submits a prompt | Create/get session, save prompt, init worker |
| 3. PostToolUse | save-hook.js | Claude uses any tool | Queue observation for AI compression |
| 4. Stop | summary-hook.js | User stops asking questions | Generate session summary |
| 5. SessionEnd | cleanup-hook.js | Session closes | Mark session completed |
Hook Configuration
Hooks are configured inplugin/hooks/hooks.json:
Stage 1: SessionStart
Timing: When user opens Claude Code or resumes session Hooks Triggered (in order):smart-install.js- Ensures dependencies are installedworker-service.cjs start- Starts the worker servicecontext-hook.js- Fetches and silently injects prior session context
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):
- Wait for worker to be available (health check, max 10 seconds)
- Call:
GET http://127.0.0.1:37777/api/context/inject?project={project} - Return formatted context as
additionalContextinhookSpecificOutput
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: TheINSERT OR IGNORE ensures the same session_id always maps to the same sessionDbId, enabling conversation continuations.
Input (via stdin):
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):- Looks up or creates session:
createSDKSession(claudeSessionId, '', '') - Gets prompt counter
- Checks privacy (skips if user prompt was entirely private)
- Strips memory tags from
tool_inputandtool_response - Queues observation for SDK agent processing
- SDK agent calls Claude to compress into structured observation
- Stores observation in database and syncs to Chroma
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):- Queues summarization for SDK agent
- Agent calls Claude to generate structured summary
- Summary stored in database with fields:
request,investigated,learned,completed,next_steps
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):- Finds session by
claudeSessionId - Marks session as ‘completed’ in database
- Broadcasts session completion event to SSE clients
src/hooks/cleanup-hook.ts
Session State Machine
Understanding session lifecycle and state transitions: Key Insights:session_idnever changes during a conversationsessionDbIdis the database primary key for the sessionpromptNumberincrements 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: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
Privacy & Tag Stripping
Dual-Tag System
Processing Pipeline
Location:src/utils/tag-stripping.ts
new-hook.jsstrips tags from user prompt before savingsave-hook.jsstrips tags from tool data before sending to worker- 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:- Initial Prompt (prompt #1): Full instructions for starting observation
- Continuation Prompt (prompt #2+): Context-only for continuing work
- Observation Prompts: Tool use data to compress into observations
- 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 configurable port (default 37777)
- 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
stripMemoryTagsFromPrompt()andstripMemoryTagsFromJson() - 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
- Session ID is Source of Truth: Never generate your own session IDs
- Idempotent Database Operations: Use
INSERT OR IGNOREfor session creation - Edge Processing for Privacy: Strip tags at hook layer before data reaches worker
- Fire-and-Forget for Non-Blocking: HTTP timeouts prevent IDE blocking
- Event-Driven, Not Polling: Zero-latency queue notification to SDK agent
- Everything Saves Always: No “orphaned” sessions
Common Pitfalls
| Problem | Root Cause | Solution |
|---|---|---|
| Session ID mismatch | Different session_id used in different hooks | Always use ID from hook input |
| Duplicate sessions | Creating new session instead of using existing | Use INSERT OR IGNORE with session_id as key |
| Blocking IDE | Waiting for full response | Use fire-and-forget with short timeouts |
| Memory tags in DB | Stripping tags in wrong layer | Strip at hook layer, before HTTP send |
| Worker not found | Health check too fast | Add retry loop with exponential backoff |
Related Documentation
- Worker Service - HTTP API and async processing
- Database Schema - SQLite tables and FTS5 search
- Privacy Tags - Using
<private>tags - Troubleshooting - Common hook issues

