1. Architecture Overview
claude-mem is a persistent memory compression framework for AI coding assistants. It intercepts IDE lifecycle events (session start, tool usage, file reads, session end), processes them through an AI observation extraction agent, stores structured observations in a local SQLite database, and re-injects compressed context into future sessions. The system operates as a local daemon with no cloud dependencies beyond the AI provider API.
The architecture follows a hook-driven event pipeline: IDE hooks capture events → Express HTTP worker processes them → SDK agent extracts observations → SQLite stores them → context builder compresses and injects them back. All state is local to the user's machine.
Architecture Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ IDE (Claude Code / Cursor / Gemini CLI / 10+ others) │
│ │
│ Hooks: │
│ SessionStart ──→ context-hook ──→ inject timeline context │
│ UserPromptSubmit ──→ session-init ──→ create/resume session │
│ PostToolUse(*) ──→ observation ──→ queue for SDK extraction │
│ PreToolUse:Read ──→ file-context ──→ inject file observations │
│ Stop ──→ summarize ──→ generate session summary │
│ SessionEnd ──→ session-complete ──→ cleanup │
└───────────────────────────┬─────────────────────────────────────────┘
│ HTTP (port 37777)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Worker Daemon (Express + Bun runtime) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SessionMgr │ │ SearchMgr │ │ ContextBuilder│ │
│ │ (sessions, │ │ (SQLite FTS, │ │ (timeline, │ │
│ │ queue) │ │ Chroma, │ │ token econ) │ │
│ └──────┬───────┘ │ hybrid) │ └───────────────┘ │
│ │ └──────────────┘ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SDKAgent │ │ GeminiAgent │ │ OpenRouter │ │
│ │ (Claude SDK) │ │ (REST API) │ │ Agent │ │
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ┌──────▼───────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Supervisor │ │ PendingMsg │ │ SSE │ │
│ │ (ProcessReg, │ │ Store │ │ Broadcaster │ │
│ │ health chk) │ │ (queue) │ │ (live UI) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ SQLite (WAL mode) │ Chroma (optional) │ │
│ │ observations, sessions│ Vector embeddings for │ │
│ │ summaries, prompts, │ semantic search │ │
│ │ pending_messages, │ │ │
│ │ schema_versions │ │ │
│ └───────────────────────┴───────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ MCP Server (stdio transport) │
│ 12+ tools: search, timeline, get_observations, smart_search, │
│ smart_unfold, smart_outline, build_corpus, list_corpora, │
│ prime_corpus, query_corpus, rebuild_corpus, reprime_corpus, │
│ __IMPORTANT │
│ Parent heartbeat for orphan detection │
└─────────────────────────────────────────────────────────────────────┘
Component Inventory
| Component | Path | Role |
|---|---|---|
| NPX CLI | src/npx-cli/ |
Install, update, uninstall, runtime commands |
| CLI Handlers | src/cli/handlers/ |
8 hook event handlers |
| CLI Adapters | src/cli/adapters/ |
IDE-specific input normalization (Claude Code, Cursor, Gemini CLI, Raw, Windsurf) |
| Worker Service | src/services/worker-service.ts |
Worker lifecycle management (start/stop/restart) |
| Worker HTTP Routes | src/services/worker/http/routes/ |
11 route classes: Chroma, Corpus, Data, Logs, Memory, Search, Session, Settings, Viewer |
| Worker Core | src/services/worker/ |
SDKAgent, GeminiAgent, OpenRouterAgent, SessionManager, SearchManager, DatabaseManager, BranchManager, SSEBroadcaster, RestartGuard, FormattingService, TimelineService, PaginationHelper |
| SQLite Layer | src/services/sqlite/ |
Database, SessionStore, SessionSearch, PendingMessageStore, migrations |
| Context Engine | src/services/context/ |
ContextBuilder, ContextConfigLoader, ObservationCompiler, TokenCalculator |
| Supervisor | src/supervisor/ |
ProcessRegistry, HealthChecker, env-sanitizer, shutdown cascade |
| SDK Prompts | src/sdk/ |
XML prompt builders, response parser |
| MCP Server | src/servers/mcp-server.ts |
Model Context Protocol server with 12+ tools |
| Shared Utilities | src/shared/ |
EnvManager, SettingsDefaultsManager, paths, worker-utils, hook-constants, timeline-formatting, transcript-parser |
| Plugin Hooks | plugin/hooks/ |
hooks.json defining IDE lifecycle event bindings |
| Plugin Modes | plugin/modes/ |
35 JSON mode files (code + 30 localized + chill) |
| Plugin Skills | plugin/skills/ |
Pathfinder, timeline-report, version-bump, smart-explore, knowledge-agent, mem-search, make-plan, do |
| Plugin UI | plugin/ui/ |
Bundled viewer (React SPA) |
| IDE Integrations | src/services/integrations/ |
CodexCliInstaller, CursorHooksInstaller, GeminiCliHooksInstaller, McpIntegrations, OpenCodeInstaller, TelegramNotifier, WindsurfHooksInstaller |
| Infrastructure | src/services/infrastructure/ |
WorktreeAdoption |
| Transcripts | src/services/transcripts/ |
TranscriptWatcher, TranscriptEventProcessor, config |
| Server | src/services/server/ |
Express Server base, ErrorHandler |
| Sync | src/services/sync/ |
ChromaSync |
| Domain | src/services/domain/ |
ModeManager |
| OpenClaw | openclaw/ |
Standalone extension package (@openclaw/claude-mem) |
| Docker | docker/claude-mem/ |
build.sh, entrypoint.sh, run.sh |
| Evals | evals/swebench/ |
SWE-bench evaluation harness |
Technology Stack
| Layer | Technology |
|---|---|
| Runtime | Bun ≥ 1.0.0 (required for bun:sqlite) |
| Language | TypeScript (compiled to ESM) |
| HTTP Server | Express 5 |
| Database | SQLite (via bun:sqlite) with WAL mode |
| Vector DB | Chroma (optional, via subprocess) |
| AI SDK | @anthropic-ai/claude-agent-sdk ^0.2.119 |
| MCP | @modelcontextprotocol/sdk ^1.29.0 |
| UI | React 19 + DOMPurify |
| Templating | Handlebars (for context templates) |
| Schema Validation | Zod 4 |
| Code Parsing | tree-sitter (20+ language grammars) |
| Build | esbuild, custom build scripts |
| Package Management | npm + Bun |
| License | AGPL-3.0 |
Data Flow: Observation Extraction
1. User invokes tool in IDE (e.g., Edit file)
2. PostToolUse hook fires → observation handler
3. Handler sends tool_name + tool_input + tool_response + cwd to worker
4. Worker's SessionManager enqueues a PendingMessage (status=pending)
5. Worker claims message (status=processing, stamps worker_pid)
6. SDKAgent (or Gemini/OpenRouter agent) receives observation prompt
7. Agent returns XML: <observation> with title, subtitle, narrative, facts, type, concepts, files
8. Parser validates XML → discriminated union: observation[] | summary | invalid
9. Observations stored in SQLite + synced to Chroma (if enabled)
10. PendingMessage confirmed (deleted from queue)
11. SSEBroadcaster notifies connected viewer clients
Data Flow: Context Injection
1. SessionStart hook fires → context-hook handler
2. ContextBuilder queries SQLite for recent observations + summaries
3. ObservationCompiler applies type/concept filtering per mode config
4. TokenCalculator computes read vs. discovery token economics
5. Compressed timeline returned as hookSpecificOutput → additionalContext
6. IDE injects timeline into the AI's system context
7. AI now knows what happened in previous sessions
2. System Requirements
Hardware
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 core | 2+ cores |
| RAM | 256 MB (worker) | 512 MB+ (worker + Chroma) |
| Disk | 100 MB (install) + growing DB | 500 MB+ |
| Network | Local only (provider API calls) | Low-latency to AI provider |
Software
| Dependency | Version | Required | Notes |
|---|---|---|---|
| Node.js | ≥ 20.0.0 | Yes | For npx CLI |
| Bun | ≥ 1.0.0 | Yes | Worker runtime (bun:sqlite) |
| Git | Any | Recommended | For worktree adoption, CLAUDE.md generation |
| Git Bash | Any | Windows only | Required for hook shell execution |
| Docker | Any | Optional | For containerized deployment |
Supported Platforms
| Platform | Status | Notes |
|---|---|---|
| macOS (Apple Silicon) | Full support | Primary development platform |
| macOS (Intel) | Full support | |
| Linux (x86_64) | Full support | |
| Windows 11 | Partial support | Known issues: #2109, #2111, #2114, #2123, #2131 |
| Windows 10 | Partial support | Same Windows caveats apply |
| Docker (Linux) | Supported | See Docker deployment section |
Note
Windows support has several known issues around path handling (spaces in usernames), shell detection (Git Bash requirement), and port management (stale sockets). macOS and Linux provide the most reliable experience.
3. Configuration Reference
Configuration Precedence
Settings are resolved in this order (first match wins):
- Environment variables (e.g.,
CLAUDE_MEM_WORKER_PORT=37778) - Settings file (
~/.claude-mem/settings.json) - Built-in defaults (in
SettingsDefaultsManager)
File Locations
| File | Path | Format | Purpose |
|---|---|---|---|
| Settings | ~/.claude-mem/settings.json |
JSON | Primary configuration |
| Credentials | ~/.claude-mem/.env |
Key=Value | AI provider API keys |
| Database | ~/.claude-mem/claude-mem.db |
SQLite | Observation storage |
| Logs | ~/.claude-mem/logs/worker-{date}.log |
Text | Daily rotating logs |
| Vector DB | ~/.claude-mem/vector-db/ |
Chroma | Semantic search index |
| Observer Sessions | ~/.claude-mem/observer-sessions/ |
Directory | SDK subprocess session data |
| Transcript Watch | ~/.claude-mem/transcript-watch.json |
JSON | Transcript watcher config |
| Cursor Registry | ~/.claude-mem/cursor-projects.json |
JSON | Cursor project tracking |
| Plugin Cache | ~/.claude/plugins/marketplaces/thedotmack/ |
Directory | Installed plugin files |
All Settings
| Setting | Type | Default | Description |
|---|---|---|---|
CLAUDE_MEM_WORKER_PORT |
string | "37777" |
Worker HTTP port |
CLAUDE_MEM_MODE |
string | "code" |
Observation mode |
CLAUDE_MEM_LOG_LEVEL |
string | "info" |
Log level: debug, info, warn, error |
CLAUDE_MEM_MODEL |
string | (provider default) | AI model for observation extraction |
CLAUDE_MEM_PROVIDER |
string | "claude" |
AI provider: claude, gemini, openrouter |
CLAUDE_MEM_CHROMA_ENABLED |
string | "true" |
Enable Chroma vector DB |
CLAUDE_MEM_CHROMA_* |
string | (various) | Chroma-specific configuration |
CLAUDE_MEM_DATA_DIR |
string | ~/.claude-mem |
Data directory override |
CLAUDE_MEM_HEALTH_TIMEOUT_MS |
string | "3000" |
Health check timeout in ms |
CLAUDE_MEM_MANAGED |
string | — | Set by worker to indicate managed mode |
CLAUDE_MEM_TELEGRAM_BOT_TOKEN |
string | — | Telegram notification bot token |
CLAUDE_MEM_TELEGRAM_CHAT_ID |
string | — | Telegram target chat ID |
CLAUDE_MEM_GEMINI_API_KEY |
string | — | Gemini API key |
CLAUDE_MEM_OPENROUTER_API_KEY |
string | — | OpenRouter API key |
CLAUDE_MEM_OPENROUTER_API_KEY (alt) |
env | — | Alias: OPENROUTER_API_KEY |
Important
The
CLAUDE_MEM_DATA_DIRsetting changes the root for all data files (database, logs, vector DB, observer sessions). Set this before first run if you need a non-default location — migrating later requires moving the database file manually.
Hook Timeouts
Defined in src/shared/hook-constants.ts:
| Constant | Value | Used By |
|---|---|---|
DEFAULT_TIMEOUT |
300s (5 min) | General hook timeout |
HEALTH_CHECK_TIMEOUT |
3s | Worker health check |
| Hook exit code 0 | SUCCESS | Continue processing |
| Hook exit code 1 | FAILURE | Non-blocking failure |
| Hook exit code 2 | BLOCKING_ERROR | Blocks the IDE operation |
Hooks Configuration
The plugin's hooks.json defines the complete hook lifecycle:
{
"hooks": {
"Setup": ["smart-install"],
"SessionStart": {
"triggers": ["startup", "clear", "compact"],
"commands": ["smart-install", "worker start", "context hook"]
},
"UserPromptSubmit": ["session-init hook"],
"PostToolUse": {
"triggers": ["*"],
"commands": ["observation hook"]
},
"PreToolUse": {
"triggers": ["Read"],
"commands": ["file-context hook"]
},
"Stop": ["summarize hook"],
"SessionEnd": ["session-complete hook"]
}
}
SQLite Configuration
Applied on database initialization (in ClaudeMemDatabase and DatabaseManager):
| Pragma | Value | Purpose |
|---|---|---|
journal_mode |
WAL | Write-Ahead Logging for concurrent reads |
synchronous |
NORMAL | Balance safety vs. performance |
foreign_keys |
ON | Enforce referential integrity |
temp_store |
memory | In-memory temp tables |
mmap_size |
256 MB | Memory-mapped I/O |
cache_size |
10,000 pages | Page cache |
4. Deployment & Scaling
Local Deployment (Standard)
The standard deployment is a single-user local installation:
npx claude-mem install # Interactive IDE setup
npx claude-mem start # Start worker daemon
All data lives in ~/.claude-mem/. The worker binds to localhost:37777. No external network access required except AI provider API calls.
Docker Deployment
Build:
cd docker/claude-mem
./build.sh # Runs npm build + docker build
Run (macOS with Keychain):
./run.sh
The run.sh script:
- Extracts OAuth credentials from the macOS Keychain
- Mounts
~/.claude-memas a persistent volume - Runs the container interactively
Run (Linux / manual credentials):
docker run -it \
-v ~/.claude-mem:/home/user/.claude-mem \
-v ~/.claude/.credentials.json:/tmp/claude-creds.json:ro \
-e CLAUDE_CREDENTIALS_FILE=/tmp/claude-creds.json \
claude-mem/claude-mem:latest
Or use an API key directly:
docker run -it \
-v ~/.claude-mem:/home/user/.claude-mem \
-e ANTHROPIC_API_KEY=sk-ant-... \
claude-mem/claude-mem:latest
The entrypoint.sh seeds credentials from the mounted file or environment variable into the container's credential store.
Warning
The Docker image expects the
~/.claude-memvolume for persistent storage. Without it, all observations are lost when the container stops.
Multi-Account Isolation
Running multiple accounts (work + personal) on the same machine requires separate data directories (#2101):
# Account 1
CLAUDE_MEM_DATA_DIR=~/.claude-mem-work CLAUDE_MEM_WORKER_PORT=37777 npx claude-mem start
# Account 2
CLAUDE_MEM_DATA_DIR=~/.claude-mem-personal CLAUDE_MEM_WORKER_PORT=37778 npx claude-mem start
Each instance gets its own database, logs, and observer sessions. Configure IDE hooks to point to the correct port.
Scaling Considerations
claude-mem is designed for single-user, single-machine operation. Scaling limits:
| Resource | Limit | Impact |
|---|---|---|
| SDK subprocesses | Hard cap: 10 | ProcessRegistry rejects spawns beyond this |
| Concurrent sessions | Soft limit via subprocess cap | Each session needs an SDK process |
| Database size | Unlimited (SQLite) | Performance degrades at ~100K+ observations without index tuning |
| Chroma index | Depends on available RAM | Large indices may slow semantic search |
| PendingMessage queue | No hard limit | Self-healing reclaim keeps queue bounded |
5. Operations
Worker Lifecycle
The worker daemon is the central component. All operations flow through it.
Start/Stop/Restart:
npx claude-mem start # Start in background
npx claude-mem stop # Graceful shutdown (SIGTERM → 5s → SIGKILL)
npx claude-mem restart # Stop then start
npx claude-mem status # Check if running
Auto-start: The SessionStart hook calls ensureWorkerRunning() which lazy-spawns the worker if it's not already running. The mechanism uses a health check (/health endpoint) with a configurable timeout.
Fail-loud counter: If the worker is unreachable, executeWithWorkerFallback increments a fail counter. After a threshold, hooks stop attempting to contact the worker and fail immediately (reducing hook latency when the worker is down).
Tip
Monitor worker health by polling
GET /healthorGET /api/readiness. The readiness endpoint includes database connectivity status.
Process Management
Supervisor: The Supervisor singleton validates the worker PID file and manages SDK subprocess lifecycle. It uses start-token verification to detect PID reuse (stale PID files pointing to a different process).
ProcessRegistry: Manages all SDK subprocesses with:
- PID tracking and POSIX process groups (pgid)
- Session reaping for cleanup
- SDK spawn factory with pre-spawn cleanup
- Pool slot waiting (backpressure when at capacity)
- Hard cap of 10 processes
- Health checker: 30-second interval pruning dead processes
Shutdown cascade:
SIGTERMsent to all registered processes- Wait 5 seconds for graceful termination
SIGKILLfor any remaining processes- On Windows: uses
tree-kill(optional dependency) for process tree termination
Note
On Linux, the Supervisor uses POSIX process groups (pgid) for reliable child cleanup. On Windows, it falls back to
tree-killwhich traverses the process tree via the Win32 API.
Log Management
Logs are written to ~/.claude-mem/logs/worker-{YYYY-MM-DD}.log with daily rotation.
# View recent logs
npm run worker:logs # Last 50 lines
# Tail in real-time
npm run worker:tail
# Via API
curl http://localhost:37777/api/logs
# Clear logs
curl -X POST http://localhost:37777/api/logs/clear
The Logger class (src/utils/logger.ts) supports levels: debug, info, warn, error. Set via CLAUDE_MEM_LOG_LEVEL.
Queue Management
The PendingMessageStore is the persistent work queue:
# Check queue status
npm run queue
# Process pending messages
npm run queue:process
# Clear all failed messages
npm run queue:clear
Self-healing: The claimNextMessage() query automatically reclaims messages from crashed workers by checking worker_pid against the live-pids set. No timer-based reaper — liveness is the truth.
Failed message cleanup: On worker startup, clearFailedOlderThan() deletes stale failed messages to keep the queue bounded and claim queries fast.
Tip
If you see the queue growing with failed messages, check the worker logs for SDK agent errors (model rate limits, credential issues, or XML parse failures).
Database Operations
Backup:
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup
SQLite WAL mode means you should also copy the -wal and -shm files if they exist, or use .backup command via SQLite CLI for a consistent snapshot.
Migrations: The MigrationRunner runs all pending schema migrations on startup. Migrations are versioned and tracked in the schema_versions table. You don't need to run migrations manually — they're applied automatically.
Direct query access:
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations"
Health Monitoring
| Endpoint | Purpose |
|---|---|
GET /health |
Basic liveness check |
GET /api/health |
Detailed health with uptime |
GET /api/readiness |
Health + database status |
GET /api/version |
Current version |
GET /api/admin/doctor |
Full diagnostic report |
GET /api/stats |
Database statistics |
GET /api/processing-status |
Active processing state |
Admin Endpoints
| Endpoint | Purpose |
|---|---|
POST /api/admin/restart |
Restart the worker |
POST /api/admin/shutdown |
Graceful shutdown |
GET /api/admin/doctor |
Diagnostic report |
POST /api/settings |
Update settings |
GET /api/settings |
Read current settings |
POST /api/mcp/toggle |
Enable/disable MCP server |
GET /api/mcp/status |
MCP server status |
GET /api/branch/status |
Current branch info |
POST /api/branch/switch |
Switch branches |
POST /api/branch/update |
Pull latest branch updates |
6. Performance
Token Economics
claude-mem tracks two metrics for every observation:
- Discovery tokens: The estimated size of the raw tool usage (input + response) that was observed
- Read tokens: The compressed observation size (title + subtitle + narrative + facts)
The TokenCalculator (src/services/context/) computes savings percentages and formats the economics display. Estimation uses 4 characters per token.
Context Injection Optimization
The ContextBuilder compresses observations for injection:
- ObservationCompiler applies SQL filters by type, concept, and mode configuration
- Multi-project support for worktrees — queries both the main project and worktree-adopted observations
- Token budgeting — the context builder tracks cumulative injection size
- Deduplication — the file-context handler deduplicates observations by session ID and applies specificity scoring
Search Performance
The SearchManager delegates to modular strategies:
| Strategy | When Used | Performance |
|---|---|---|
SQLiteSearchStrategy |
Filter-only queries (type, date, file) | Fast — indexed queries |
ChromaSearchStrategy |
Semantic queries | Depends on index size |
HybridSearchStrategy |
Metadata filter + semantic ranking | Combined latency |
Pagination: The PaginationHelper uses the LIMIT+1 trick to detect hasMore without a COUNT(*) query.
Database Performance Tuning
The SQLite database is configured for maximum read performance:
- WAL mode: Allows concurrent readers during writes
- Memory-mapped I/O: 256 MB mmap reduces syscall overhead
- Page cache: 10,000 pages in memory
- In-memory temp store: Temporary tables don't hit disk
For large installations (10K+ observations), consider periodic VACUUM:
sqlite3 ~/.claude-mem/claude-mem.db "VACUUM"
Worker Resource Usage
| Component | Typical Memory | Notes |
|---|---|---|
| Worker (Express) | ~50-100 MB | Base process |
| SDK subprocess | ~100-200 MB each | Up to 10 concurrent |
| Chroma subprocess | ~200-500 MB | Vector index in memory |
| SQLite | ~10-50 MB | Page cache + mmap |
Warning
With Chroma enabled and multiple active sessions, peak memory can reach 2+ GB. On memory-constrained systems, disable Chroma (
CLAUDE_MEM_CHROMA_ENABLED=false) and limit concurrent sessions.
7. Security
Credential Isolation
The EnvManager (src/shared/EnvManager.ts) provides credential isolation:
- Credentials stored separately in
~/.claude-mem/.env - Blocklist approach:
ANTHROPIC_API_KEYandCLAUDECODE*variables are stripped from subprocess environments buildIsolatedEnv()constructs a clean environment for SDK subprocessesgetCredential()provides read access to stored credentials
Subprocess Environment Sanitization
The env-sanitizer (src/supervisor/env-sanitizer.ts) strips additional sensitive variables:
CLAUDECODE_*variables (all)CLAUDE_CODE_*variables (all)- Preserved:
OAUTH_TOKENandGIT_BASH_PATH(needed for operation)
Caution
Proxy environment variables (
HTTP_PROXY,HTTPS_PROXY,ALL_PROXY) are NOT stripped by the sanitizer. Worker subprocesses inherit them, which can cause stalls when the proxy is unreachable (#2115). Unset these before starting the worker if your network uses a proxy.
Input Validation
- Branch names:
BranchManager.isValidBranchName()validates against^[a-zA-Z0-9][a-zA-Z0-9._/-]*$and rejects..sequences (prevents command injection via git operations) - File paths: Adapter layers validate
cwdinput —AdapterRejectedInputerror for invalid working directories - Hook responses: Standard
{ continue: true, suppressOutput: true }JSON response prevents hook output from leaking into IDE output - JSON integrity:
json-utils.tsrefuses to overwrite corrupt JSON files — detection before write prevents silent data loss
Privacy
<private>...</private>tags: Content wrapped in privacy tags is stripped before observation extraction- Observer session isolation: Observer agent sessions are tracked separately (
OBSERVER_SESSIONS_DIR) and filtered from user-facing queries - Project exclusion: Configurable project exclusion prevents observations from specific directories
Network Exposure
The worker binds to localhost only — it is not accessible from other machines on the network. External access requires explicit port forwarding or reverse proxy configuration.
The only external network calls are:
- AI provider API calls (Claude/Gemini/OpenRouter) for observation extraction
- Telegram API calls (if configured)
- GitHub API calls (viewer version check)
Warning
The worker's HTTP API has no authentication. Anyone with local access to the machine can query and modify observations. This is by design for single-user operation, but be aware in shared-machine scenarios.
8. Developer Internals
Repository Structure
claude-mem/
├── src/
│ ├── cli/
│ │ ├── adapters/ # IDE input normalization (claude-code, cursor, gemini-cli, raw, windsurf)
│ │ ├── handlers/ # 8 hook event handlers (context, session-init, observation, file-context, summarize, session-complete, user-message, file-edit)
│ │ └── claude-md-commands.ts # CLAUDE.md generation/cleanup
│ ├── hooks/
│ │ └── hook-response.ts # Standard hook response constant
│ ├── integrations/
│ │ └── opencode-plugin/ # OpenCode plugin entry point
│ ├── npx-cli/
│ │ ├── commands/ # install, runtime, uninstall, ide-detection
│ │ ├── utils/ # bun-resolver
│ │ └── index.ts # CLI entry point
│ ├── sdk/
│ │ ├── parser.ts # XML response parser (observation[], summary, invalid)
│ │ └── prompts.ts # XML prompt builders (init, observation, summary, continuation)
│ ├── servers/
│ │ └── mcp-server.ts # MCP server with 12+ tools
│ ├── services/
│ │ ├── context/ # ContextBuilder, ContextConfigLoader, ObservationCompiler, TokenCalculator
│ │ ├── domain/ # ModeManager
│ │ ├── infrastructure/ # WorktreeAdoption
│ │ ├── integrations/ # 7 IDE installers + TelegramNotifier + McpIntegrations
│ │ ├── server/ # Express Server base, ErrorHandler
│ │ ├── sqlite/ # Database, SessionStore, SessionSearch, PendingMessageStore, migrations
│ │ ├── sync/ # ChromaSync
│ │ ├── transcripts/ # TranscriptWatcher, TranscriptEventProcessor
│ │ ├── worker/ # Core worker: SDKAgent, GeminiAgent, OpenRouterAgent, SessionManager, SearchManager, etc.
│ │ └── worker-service.ts # Worker lifecycle management (1365+ lines)
│ ├── shared/ # EnvManager, SettingsDefaultsManager, paths, worker-utils, hook-constants
│ ├── supervisor/ # ProcessRegistry, health-checker, env-sanitizer, shutdown
│ ├── types/ # Shared type definitions
│ ├── ui/
│ │ └── viewer/ # React SPA (App.tsx, components, hooks, utils)
│ └── utils/ # Logger, json-utils, cursor-utils, claude-md-utils
├── plugin/
│ ├── hooks/ # hooks.json
│ ├── modes/ # 35 JSON mode files
│ ├── scripts/ # worker-service.cjs, mcp-server.cjs, smart-install
│ ├── skills/ # 8 skills: pathfinder, timeline-report, version-bump, smart-explore, knowledge-agent, mem-search, make-plan, do
│ ├── ui/ # Bundled viewer assets
│ └── .mcp.json # MCP server declaration
├── openclaw/ # @openclaw/claude-mem extension package
├── ragtime/ # Ragtime transcript processor
├── cursor-hooks/ # Cursor-specific hook scripts
├── docker/claude-mem/ # Docker build/run scripts
├── evals/swebench/ # SWE-bench evaluation harness
├── scripts/ # Build scripts, translation, bug-report tool
├── tests/ # Comprehensive test suite
│ ├── cli/ # Handler tests, adapter tests
│ ├── context/ # Context builder tests
│ ├── infrastructure/ # Plugin-disabled check
│ ├── integration/ # Integration tests
│ ├── sdk/ # Parser tests
│ ├── server/ # Server tests
│ ├── services/ # SQLite, queue, sync tests
│ ├── shared/ # Settings, utils tests
│ ├── sqlite/ # Database tests
│ ├── supervisor/ # Supervisor tests
│ ├── utils/ # Utility tests
│ └── worker/ # Worker tests (agents, routes, middleware, search)
├── docs/
│ ├── public/ # MDX documentation site
│ ├── i18n/ # 31 language README translations
│ ├── reports/ # Bug investigation reports
│ └── context/ # Context documentation
├── install/ # Installation page/assets
└── PATHFINDER-*/ # Architecture exploration documents
Module Deep-Dive: SDK Agent Pipeline
The SDK agent pipeline is the core observation extraction mechanism:
1. Prompt Construction (src/sdk/prompts.ts):
buildInitPrompt(mode)— Initial system prompt establishing the observer role, XML output format, mode-specific type/concept definitionsbuildObservationPrompt(toolName, toolInput, toolResponse, mode)— Observation extraction prompt for a specific tool usebuildSummaryPrompt(lastAssistantMessage, mode)— Session summary promptbuildContinuationPrompt(mode)— Continuation prompt when the agent needs to generate more observations
All prompts are mode-aware — the ModeManager loads the active mode's JSON file and injects customized placeholders, footer text, and language requirements.
2. Agent Execution:
Three agent implementations share the same XML observation format:
SDKAgent— Uses@anthropic-ai/claude-agent-sdk'squery()function to spawn a Claude subprocess. Event-driven (no polling). Managed by the ProcessRegistry.GeminiAgent— Direct REST calls tohttps://generativelanguage.googleapis.com/v1/models. Handles free-tier RPM limits per model.OpenRouterAgent— REST calls tohttps://openrouter.ai/api/v1/chat/completions. OpenAI-compatible message format. Default context limit: 20 messages / 100K estimated tokens.
3. Response Parsing (src/sdk/parser.ts):
parseAgentXml() returns a discriminated union:
{ kind: 'observation', observations: Observation[] }— One or more extracted observations{ kind: 'summary', summary: SessionSummary }— Session progress summary{ kind: 'invalid', reason: string }— Parse failure- Handles
<skip_summary/>as a first-class case (agent decided no summary needed)
4. Storage and Sync:
Parsed observations are:
- Stored in SQLite via
SessionStore.storeObservation() - Synced to Chroma via
ChromaSync(if enabled) - SSE-broadcast to connected viewer clients
Module Deep-Dive: PendingMessageStore
The PendingMessageStore (src/services/sqlite/PendingMessageStore.ts) is the persistence layer for the observation queue:
Lifecycle:
enqueue()—INSERT OR IGNORE(tool_use_id UNIQUE constraint prevents duplicates)claimNextMessage()— AtomicUPDATE ... WHERE id = (subselect)with worker PID stampingconfirmProcessed()—DELETEafter successful storage- Self-healing:
claimNextMessagereclaims rows whereworker_pid NOT IN (live_pids)
Key design decisions:
- No timer-based reaping — liveness is checked at claim time, not by a background process
- PID-based crash detection —
LiveWorkerPidsProviderreturns the set of alive worker PIDs - Idempotent enqueue —
INSERT OR IGNOREon the(content_session_id, tool_use_id)UNIQUE index - Max retries: 3 per message (configurable)
- Terminal states:
failed(narrow: onlyprocessingrows),abandoned(wide:pending+processing)
Module Deep-Dive: Context Builder
The context system (src/services/context/) compresses observation history for injection:
ContextBuilder— Orchestrator that queries SQLite and formats the timelineContextConfigLoader— Loads settings with mode-based filtering (type/concept exclusions)ObservationCompiler— SQL query builder with:- Type filtering per mode config
- Concept filtering
- Multi-project support (main project + adopted worktree observations)
- Date range filtering
TokenCalculator— Computes read tokens vs. discovery tokens, savings percentage
Module Deep-Dive: Search Infrastructure
The search system uses a strategy pattern:
SearchManager (facade)
└── SearchOrchestrator (strategy selection)
├── SQLiteSearchStrategy — Filter-only queries
├── ChromaSearchStrategy — Vector semantic search
└── HybridSearchStrategy — Filters + semantic ranking
Additional components:
ResultFormatter— Consistent output formattingTimelineBuilder— Chronological timeline constructionFormattingService— Table format matching context-generator style
Module Deep-Dive: IDE Integration Installers
Each supported IDE has a dedicated installer in src/services/integrations/:
| Installer | IDE | Method |
|---|---|---|
| Built-in (hooks.json) | Claude Code | Native lifecycle hooks |
CursorHooksInstaller |
Cursor | hooks.json + MCP config + project registry + .cursor/rules |
GeminiCliHooksInstaller |
Gemini CLI | Hook mapping + GEMINI.md context |
OpenCodeInstaller |
OpenCode | Plugin hooks |
WindsurfHooksInstaller |
Windsurf | hooks.json merging |
CodexCliInstaller |
Codex CLI | Transcript watching (no hooks) |
McpIntegrations |
Various | MCP server configuration |
TelegramNotifier |
N/A | Push notifications |
Cursor specifics:
- Project registry at
~/.claude-mem/cursor-projects.json - Auto-updates
.cursor/rulesafter summary generation viaupdateCursorContextForProject() - MCP server script at
plugin/scripts/mcp-server.cjs - Detects Bun executable across macOS, Linux, and Windows paths
Codex CLI specifics:
- Transcript-only approach — no hooks, watches
~/.codex/sessions/**/*.jsonl - Merges watch config into
~/.claude-mem/transcript-watch.json(preserves other watches) - Context via workspace-local
AGENTS.mdfiles - Legacy global
~/.codex/AGENTS.mdcontext is cleaned up on install
Code Patterns and Conventions
Module organization:
- Named re-export facades (e.g.,
Search.tsre-exports./search/index.js) - Route classes extend
BaseRouteHandler - Singleton patterns:
Supervisor,DatabaseManager(legacy),Logger - New code uses
ClaudeMemDatabaseclass (deprecating singletonDatabaseManager)
Error handling:
AppErrorextendsErrorwith HTTP status codesasyncHandlerwraps Express route handlers for promise rejectionAdapterRejectedInputfor invalid IDE inputDryRunRollbackfor worktree adoption dry runs
TypeScript patterns:
- ESM modules (
"type": "module") bun:sqlitefor database access (Bun-specific)- Zod 4 for runtime validation
- Discriminated unions for parse results
- Strict null checks
Build system:
scripts/build-hooks.js— esbuild bundles for hooksscripts/sync-plugin-manifests.js— Syncs version across package.json filesscripts/sync-marketplace.cjs— Copies plugin to marketplace directoryesbuildfor all bundling
Testing Strategy
Tests use Bun's built-in test runner (bun test):
bun test # All tests
bun test tests/sqlite/ # SQLite layer tests
bun test tests/worker/ # Worker tests
bun test tests/context/ # Context builder tests
bun test tests/server/ # Server tests
bun test tests/sdk/ # Parser tests
Test organization mirrors source structure:
tests/cli/handlers/— Hook handler teststests/cli/adapters/— IDE adapter teststests/worker/agents/— Agent teststests/worker/search/— Search strategy teststests/worker/http/routes/— HTTP route teststests/worker/middleware/— Middleware teststests/sqlite/— Database layer teststests/services/sqlite/observations/— Observation storage teststests/services/queue/— Queue teststests/services/sync/— Chroma sync teststests/context/formatters/— Context formatter teststests/shared/— Shared utility teststests/infrastructure/— Plugin state teststests/supervisor/— Supervisor tests
Type checking:
npm run typecheck # Root + Viewer
npm run typecheck:root # Root tsconfig only
npm run typecheck:viewer # Viewer tsconfig only
Potential Improvements
Based on open GitHub issues and code patterns:
-
Windows reliability — Multiple open issues (#2109, #2111, #2114, #2123, #2131) around path handling, port management, and shell detection. A comprehensive Windows test suite would catch regressions.
-
Session timeout configurability — Currently hardcoded
MAX_SESSION_WALL_CLOCK_MSat 4 hours (#2098, #2127). Should be exposed as a setting. -
Chroma subprocess lifecycle — The MCP retry logic can spawn multiple Chroma subprocesses without killing previous ones (#2102). Needs proper subprocess lifecycle management.
-
Observer session isolation — Observer prompts leaking into
user_prompts(#2104) and SSE events (#2118) indicate incomplete session boundary enforcement. -
PreToolUse:Read hook timeout — The 2000-second timeout (#2100) should be reduced to prevent blocking the IDE when the worker hangs.
-
Environment variable filtering — Configurable whitelist requested (#2099) instead of the current blocklist approach, which can miss proxy variables (#2115).
-
Multi-account support — No built-in isolation for work/personal accounts (#2101). The current workaround (separate DATA_DIR) is manual.
9. Integration Points
MCP Server
The MCP server (src/servers/mcp-server.ts) exposes claude-mem's capabilities to any MCP-compatible client via stdio transport.
Server declaration (plugin/.mcp.json):
{
"mcpServers": {
"mcp-search": {
"type": "stdio",
"command": "bun",
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.cjs"]
}
}
}
Available tools:
| Tool | Parameters | Purpose |
|---|---|---|
__IMPORTANT |
topic: workflow, search_params, examples, all |
Workflow guide and onboarding |
search |
query, obs_type, dateStart, dateEnd, orderBy, limit, offset, concept |
Search observations |
timeline |
query, dateStart, dateEnd |
Chronological timeline |
get_observations |
ids (array) |
Batch fetch by ID |
smart_search |
query |
Semantic search via Chroma |
smart_unfold |
id |
Expand observation context |
smart_outline |
query |
Structured outline from results |
build_corpus |
name, query |
Create knowledge corpus |
list_corpora |
— | List all corpora |
prime_corpus |
name |
AI-analyze corpus |
query_corpus |
name, query |
Query a corpus |
rebuild_corpus |
name |
Rebuild corpus index |
reprime_corpus |
name |
Re-analyze corpus |
Orphan detection: The MCP server uses a parent heartbeat mechanism to detect when the IDE process has died, allowing clean self-termination.
Worker HTTP API Reference
Complete API surface extracted from route definitions:
Health & Admin:
| Method | Path | Purpose |
|---|---|---|
GET |
/health |
Liveness check |
GET |
/api/health |
Detailed health |
GET |
/api/readiness |
Health + DB status |
GET |
/api/version |
Version info |
GET |
/api/instructions |
Worker instructions |
POST |
/api/admin/restart |
Restart worker |
POST |
/api/admin/shutdown |
Shutdown worker |
GET |
/api/admin/doctor |
Full diagnostic |
Data & Observations:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/observations |
List observations (paginated) |
GET |
/api/observation/:id |
Single observation |
GET |
/api/observations/by-file |
By file path |
POST |
/api/observations/batch |
Batch fetch |
GET |
/api/summaries |
List summaries |
GET |
/api/prompts |
List prompts |
GET |
/api/prompt/:id |
Single prompt |
GET |
/api/stats |
Database statistics |
GET |
/api/projects |
Project list |
GET |
/api/processing-status |
Active processing |
POST |
/api/processing |
Submit processing task |
POST |
/api/import |
Bulk import |
Search:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/search |
Full-text search |
GET |
/api/timeline |
Timeline view |
GET |
/api/decisions |
Decision observations |
GET |
/api/changes |
Change observations |
GET |
/api/how-it-works |
How-it-works content |
GET |
/api/search/observations |
Search observations |
GET |
/api/search/sessions |
Search sessions |
GET |
/api/search/prompts |
Search prompts |
GET |
/api/search/by-concept |
By concept |
GET |
/api/search/by-file |
By file |
GET |
/api/search/by-type |
By type |
GET |
/api/search/help |
Search help |
GET |
/api/timeline/by-query |
Timeline filtered by query |
Context:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/context/recent |
Recent context |
GET |
/api/context/timeline |
Context timeline |
GET |
/api/context/preview |
Context preview |
GET |
/api/context/inject |
Context injection payload |
POST |
/api/context/semantic |
Semantic context query |
Sessions:
| Method | Path | Purpose |
|---|---|---|
GET |
/sessions/:id/status |
Session status |
DELETE |
/sessions/:id |
Delete session |
POST |
/sessions/:id/complete |
Complete session |
GET |
/api/sessions/status |
All sessions status |
POST |
/api/sdk-sessions/batch |
Batch SDK session operations |
Settings & Configuration:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/settings |
Read settings |
POST |
/api/settings |
Update settings |
GET |
/api/mcp/status |
MCP status |
POST |
/api/mcp/toggle |
Toggle MCP |
GET |
/api/branch/status |
Git branch info |
POST |
/api/branch/switch |
Switch branches |
POST |
/api/branch/update |
Pull branch updates |
Memory:
| Method | Path | Purpose |
|---|---|---|
POST |
/api/memory/save |
Save manual memory |
Corpus:
| Method | Path | Purpose |
|---|---|---|
POST |
/api/corpus |
Create corpus |
GET |
/api/corpus |
List corpora |
GET |
/api/corpus/:name |
Get corpus |
DELETE |
/api/corpus/:name |
Delete corpus |
POST |
/api/corpus/:name/rebuild |
Rebuild corpus |
POST |
/api/corpus/:name/prime |
Prime corpus |
POST |
/api/corpus/:name/query |
Query corpus |
POST |
/api/corpus/:name/reprime |
Re-prime corpus |
Chroma:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/chroma/status |
Chroma status |
Logs:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/logs |
Read logs |
POST |
/api/logs/clear |
Clear logs |
Viewer & SSE:
| Method | Path | Purpose |
|---|---|---|
GET |
/ |
Viewer SPA |
GET |
/stream |
SSE event stream |
Transcript Watcher Integration
For IDEs without hook support, claude-mem offers transcript watching:
Configuration (~/.claude-mem/transcript-watch.json):
{
"version": 1,
"schemas": {
"codex": { "version": 1, "format": "jsonl" }
},
"watches": [
{
"name": "codex",
"glob": "~/.codex/sessions/**/*.jsonl",
"schema": "codex"
}
],
"stateFile": "~/.claude-mem/transcript-watch-state.json"
}
Components:
TranscriptWatcher—FileTailerthat monitors glob patterns for new JSONL/JSON contentTranscriptEventProcessor— Processes transcript events and maps them to observation ingestion- Supports Codex CLI JSONL and Gemini CLI JSON formats
OpenClaw Extension
The openclaw/ directory contains a standalone extension package (@openclaw/claude-mem) that integrates with the OpenClaw platform:
- Communicates via SSE stream to the worker
- Runs as a private npm package
- Built and tested independently (
tsc+node --test)
Plugin Skills
The plugin includes 8 skills in plugin/skills/:
| Skill | Purpose |
|---|---|
pathfinder |
Architecture exploration and analysis |
timeline-report |
Generate timeline reports |
version-bump |
Version bump automation with scripts |
smart-explore |
Intelligent codebase exploration |
knowledge-agent |
Knowledge base management |
mem-search |
Memory search interface |
make-plan |
Planning assistance |
do |
Task execution |
Ragtime
The ragtime/ directory contains a transcript processor that:
- Reads from
RAGTIME_CORPUS_PATH - Connects to worker on
CLAUDE_MEM_WORKER_PORT - Processes transcripts with configurable max age, file limits, and session delays
- Supports mode-aware observation extraction
Troubleshooting (Admin)
Worker Won't Start
- Check port availability:
lsof -i :37777 # macOS/Linux netstat -an | grep 37777 # Windows - Check Bun installation:
bun --version - Check logs:
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log - Check PID file:
cat ~/.claude-mem/worker.pid
Database Corruption
Symptoms: SQLITE_CORRUPT, SQLITE_NOTADB, unexpected query errors.
- Stop the worker
- Back up the database:
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.corrupt - Attempt recovery:
sqlite3 ~/.claude-mem/claude-mem.db ".recover" | sqlite3 ~/.claude-mem/claude-mem-recovered.db - Replace the database and restart
SDK Agent Not Extracting Observations
- Check provider credentials:
- Claude: OAuth token valid? (
~/.claude/.credentials.json) - Gemini: API key set? (
CLAUDE_MEM_GEMINI_API_KEY) - OpenRouter: API key set? (
CLAUDE_MEM_OPENROUTER_API_KEY)
- Claude: OAuth token valid? (
- Check process count:
GET /api/processing-status - Check for hard cap: logs show "Hard cap exceeded" if at 10 processes
- Check PendingMessage queue:
npm run queue
Caution
If the SDK agent fails repeatedly, messages accumulate in the pending queue. The
clearFailedOlderThan()method cleans up on restart, but a persistent failure (e.g., expired credentials) will keep generating failed messages. Fix the root cause before restarting.
High Memory Usage
- Check Chroma:
GET /api/chroma/status— disable if leaking (#2102) - Count SDK processes: check logs for ProcessRegistry spawn count
- Check for restart loops: RestartGuard logs will show trip conditions
- Consider reducing
MAX_CONCURRENT(default context limit: 20 messages per agent)
Migration Failures
If a migration fails on startup:
- Check the
schema_versionstable for the last successful version - Examine the migration runner logs
- The migration runner is idempotent — restarting will retry failed migrations
- In extreme cases, back up and recreate the database
Quick Reference
npm Scripts
| Script | Purpose |
|---|---|
npm run build |
Build hooks and sync manifests |
npm run dev |
Build + sync marketplace + restart worker |
npm run test |
Run all tests (bun test) |
npm run typecheck |
TypeScript type checking |
npm run worker:start |
Start worker via bun |
npm run worker:stop |
Stop worker |
npm run worker:restart |
Restart worker |
npm run worker:status |
Worker status |
npm run worker:logs |
View recent logs |
npm run queue |
Check queue status |
npm run queue:process |
Process pending messages |
npm run queue:clear |
Clear failed messages |
npm run claude-md:regenerate |
Regenerate CLAUDE.md files |
npm run claude-md:dry-run |
Preview CLAUDE.md changes |
npm run cursor:install |
Install Cursor integration |
npm run cursor:uninstall |
Remove Cursor integration |
npm run cursor:status |
Cursor integration status |
npm run translate-readme |
Translate README to other languages |
npm run bug-report |
Generate bug report |
npm run release:patch |
Release patch version |
npm run release:minor |
Release minor version |
npx CLI Commands
| Command | Purpose |
|---|---|
npx claude-mem install |
Interactive installation |
npx claude-mem update / upgrade |
Update to latest |
npx claude-mem uninstall / remove |
Remove installation |
npx claude-mem start |
Start worker |
npx claude-mem stop |
Stop worker |
npx claude-mem restart |
Restart worker |
npx claude-mem status |
Worker status |
npx claude-mem search |
Search observations |
npx claude-mem adopt |
Adopt worktree observations |
npx claude-mem transcript watch |
Start transcript watcher |
npx claude-mem version |
Show version |
npx claude-mem help |
Show help |
Key File Paths
| Path | Purpose |
|---|---|
~/.claude-mem/ |
Data directory root |
~/.claude-mem/claude-mem.db |
SQLite database |
~/.claude-mem/settings.json |
Configuration |
~/.claude-mem/.env |
Credentials |
~/.claude-mem/logs/ |
Daily rotating logs |
~/.claude-mem/vector-db/ |
Chroma vector index |
~/.claude-mem/observer-sessions/ |
SDK subprocess data |
~/.claude-mem/transcript-watch.json |
Transcript watcher config |
~/.claude-mem/cursor-projects.json |
Cursor project registry |
~/.claude/plugins/marketplaces/thedotmack/ |
Installed plugin |
Key Constants
| Constant | Value | Source |
|---|---|---|
| Default port | 37777 | SettingsDefaultsManager |
| Hook timeout | 300s | hook-constants.ts |
| Health check timeout | 3s | hook-constants.ts |
| Process hard cap | 10 | process-registry.ts |
| Health check interval | 30s | health-checker.ts |
| Restart window | 60s | RestartGuard.ts |
| Max windowed restarts | 10 | RestartGuard.ts |
| Max consecutive failures | 5 | RestartGuard.ts |
| Decay after success | 5 min | RestartGuard.ts |
| SQLite mmap size | 256 MB | Database.ts |
| SQLite cache pages | 10,000 | Database.ts |
| Max pending retries | 3 | PendingMessageStore.ts |
| Shutdown grace period | 5s | shutdown.ts |
| Git command timeout | 300s | BranchManager.ts |
| npm install timeout | 600s | BranchManager.ts |
| Token estimate | 4 chars/token | Multiple files |