Claude Memory — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Claude Memory (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A persistent memory system for Claude Code, implemented as an MCP server. Gives Claude long-term recall across sessions by indexing curated notes, thousands of past conversation archives, and external codebases with hybrid keyword + vector search.
Claude Code sessions are stateless. Every new conversation starts from scratch. You end up re-explaining context that Claude already helped you figure out last week.
claude-memory runs as an MCP server that Claude Code connects to automatically. It provides 13 tools across four categories:
Search & retrieval:
Code intelligence:
Read & write:
Health:
All data stays local in ~/.claude-memory/. No external API calls for search. Embeddings are generated locally using three models: bge-base-en-v1.5 (768-dim) for memory search, nomic-embed-text-v1.5 (768-dim) for codebase indexing, and all-MiniLM-L6-v2 (384-dim) for the Node.js batch indexer. Optional TurboQuant 4-bit quantization provides 8x storage compression with >=0.998 recall@10.
git clone https://github.com/NathanNorman/claude-memory.git
cd claude-memory
npm install
npm run buildThe MCP server runs in Python. Set up a venv with the required packages:
python3 -m venv ~/.claude-memory/graphiti-venv
~/.claude-memory/graphiti-venv/bin/pip install mcp sentence-transformers torch numpyAdd to your MCP settings (e.g., ~/.claude.json):
{
"mcpServers": {
"unified-memory": {
"type": "stdio",
"command": "/bin/bash",
"args": ["/path/to/claude-memory/unified-mcp-launcher.sh"]
}
}
}# Build the search index from conversation archives
node dist/reindex-cli.jsClaude Code will automatically have access to all 13 tools. No additional configuration needed.
The system has three subsystems: a Python MCP server (runtime), a Node.js indexer (batch), and a webhook pipeline (real-time remote indexing). All three share a single SQLite database in WAL mode.
~/claude-memory/ # This repo (source code)
├── src/
│ ├── unified_memory_server.py # Python MCP server (runtime, 13 tools)
│ ├── server.ts # Node.js MCP server entry point
│ ├── tools.ts # MCP tool handlers + Zod schemas
│ ├── types.ts # Shared TypeScript types
│ │
│ │ # Search
│ ├── search.ts # Search orchestration (keyword + vector)
│ ├── hybrid.ts # FTS5 query building, BM25 scoring, RRF merge
│ ├── db.ts # SQLite operations, migrations
│ ├── embeddings.ts # Embedding generation (ONNX, transformers.js)
│ ├── quantize.py # TurboQuant 4-bit quantization (WHT + Lloyd-Max)
│ │
│ │ # Chunking
│ ├── chunker.ts # Exchange-aware conversation chunking
│ ├── semantic-chunker.ts # Boundary scoring + variance-minimizing DP
│ ├── semantic-markdown-chunker.ts # 3-stage markdown chunking pipeline
│ ├── llm-boundary-scorer.ts # LLM-based scoring (coprime windows 16, 11)
│ ├── llm-client.ts # OpenAI-compatible LLM client
│ ├── code_chunker.py # Code-aware chunking (AST/regex/size-based)
│ ├── conversation-parser.ts # JSONL -> structured exchange pairs
│ │
│ │ # Code intelligence
│ ├── ast_parser.py # tree-sitter (Java/Kotlin/TS) + ast (Python)
│ ├── import_resolver.py # Import string -> file path resolution
│ ├── call_resolver.py # 6-strategy call resolution cascade
│ ├── scip_parser.py # Optional SCIP indexer integration (Tier 2)
│ ├── build_parser.py # Gradle/Maven/pip/npm dependency extraction
│ │
│ │ # Webhook pipeline
│ ├── webhook_server.py # FastAPI webhook receiver (HMAC-SHA256)
│ ├── job_queue.py # SQLite-backed job queue with deduplication
│ ├── index_worker.py # Background worker (bare mirror indexing)
│ ├── mirror_manager.py # Bare git clone/fetch management
│ ├── poll_repos.py # Polling fallback (git ls-remote cron)
│ │
│ │ # Tools
│ ├── doctor-cli.ts # Database diagnostics and repair
│ ├── reindex-cli.ts # Batch reindexing CLI
│ ├── indexer.ts # File scanning, staleness detection
│ ├── integration.test.ts # Integration tests
│ └── prompts/ # LLM scoring prompts
│ ├── boundary-score-system.txt
│ └── boundary-score-user.txt
│
├── scripts/
│ ├── codebase-index.py # External codebase indexer
│ ├── index_session.py # Real-time session indexer (SessionEnd hook)
│ ├── conversation_parser.py # JSONL conversation parser (Python)
│ ├── cross_repo_deps.py # Cross-repo dependency graph builder
│ ├── build-reference-db.py # Addon reference database builder
│ ├── migrate_to_quantized.py # TurboQuant sidecar file generation
│ ├── backfill_entity_relationships.py # Entity graph backfill
│ ├── backfill_signals.py # Signal backfill utility
│ ├── bulk_index.py # Bulk indexing utility
│ ├── ingest_archive.py # Archive ingestion
│ ├── summary_refinement.py # LLM judge-refine summary loop
│ ├── summary_prompts.py # Summary/judge/refiner prompts
│ ├── summary_llm.py # LLM client for summaries (claude CLI)
│ ├── start-webhook-server.sh # Webhook server launcher
│ ├── index_missing_sessions.sh # Catch-up indexing for missed sessions
│ ├── restore_pre_turboquant.sh # Rollback script for quantization
│ └── test_*.py # Test files (14 test modules)
│
├── benchmarks/
│ ├── retrieval_bench.py # Recall@5/10 benchmark harness
│ ├── corpus.json # 50-document synthetic corpus
│ ├── baseline.json # 2-signal baseline (R@5=0.680)
│ └── baseline-4signal.json # 4-signal baseline (R@5=0.777)
│
└── unified-mcp-launcher.sh # MCP server launcher
~/.claude-memory/ # Runtime data directory
├── MEMORY.md # Long-term curated knowledge
├── memory/
│ └── YYYY-MM-DD.md # Daily structured logs
├── index/
│ ├── memory.db # SQLite search index (FTS5 + embeddings)
│ ├── reindex.lock # File lock for serialized writes
│ ├── packed_vectors.bin # TurboQuant 4-bit sidecar (optional)
│ ├── rerank_matrix.f32 # Float32 rerank sidecar (optional)
│ └── quantization.json # Quantization metadata (optional)
├── mirrors/ # Bare git clones (webhook pipeline)
├── conversation-archive/ # JSONL backups (rsync'd every 30min)
├── backups/ # Daily DB backups
└── graphiti-venv/ # Python virtualenvCurated memory files use a 3-stage semantic markdown chunking pipeline:
Conversation archives use exchange-aware chunking:
Source code (via codebase indexer) uses language-aware chunking:
ast)When memory_write is called, the server:
bge-base-en-v1.5 (768-dim), quantizes to 4-bit, and writes to the chunks table (immediate vector search coverage)No waiting for the Node.js reindexer -- written memories are searchable via both backends immediately.
The code intelligence subsystem builds a call graph and type hierarchy from indexed codebases:
AST extraction (ast_parser.py): tree-sitter for Java, Kotlin, and TypeScript; stdlib ast for Python. Extracts imports (with type classification), symbol declarations (classes, interfaces, functions, methods with line numbers), call sites, and type hierarchy (extends, implements, delegation).
Call resolution (call_resolver.py): A 6-strategy cascade resolves each extracted call site to a target symbol, short-circuiting on first match:
| Priority | Strategy | Confidence |
|---|---|---|
| 1 | Import-map exact match | 0.95 |
| 2 | Import-map suffix fallback | 0.85 |
| 3 | Same-module prefix match | 0.90 |
| 4 | Unique name project-wide | 0.75 |
| 5 | Suffix + directory distance | 0.55 |
| 6 | Fuzzy string similarity | 0.30-0.40 |
SCIP integration (scip_parser.py): Optional Tier 2 indexing via scip-java, scip-typescript, or scip-python. SCIP edges (0.95 confidence) replace tree-sitter edges for the same source/target file pair.
Cross-repo dependencies (cross_repo_deps.py + build_parser.py): Parses Gradle KTS/Groovy (including version catalog TOML), Maven (with property interpolation), pyproject.toml, requirements.txt, and package.json into repo_dependency edges.
For repositories on GitHub rather than the local machine, the webhook pipeline provides push-triggered incremental indexing:
webhook_server.py (FastAPI, HMAC-SHA256 verified)Polling fallback via poll_repos.py checks tracked repos via git ls-remote and enqueues jobs when remote HEAD changes.
Conversation sessions can be automatically summarized using an LLM judge-refine loop:
files.summary column for search result enrichmentControlled via MEMORY_SUMMARY_ENABLED=1 and MEMORY_SUMMARY_MODEL env vars.
External repositories can be indexed for semantic search:
# Full index
python3 scripts/codebase-index.py --path ~/my-repo --name my-repo
# Incremental update (only changed files)
python3 scripts/codebase-index.py --path ~/my-repo --name my-repo --update
# Low-impact mode (throttled, nice'd)
python3 scripts/codebase-index.py --path ~/my-repo --name my-repo --throttle
# List indexed codebases
python3 scripts/codebase-index.py --list
# Remove
python3 scripts/codebase-index.py --remove --name my-repoCodebase chunks are stored in the main chunks table with file_path prefixed by codebase:<name>/. A PreToolUse:Write hook surfaces similar existing code when creating new source files, preventing duplicate implementations.
Skills and plugins can ship pre-built .db files containing searchable reference material. The server discovers these at startup and makes them searchable via memory_search(source="<name>").
# Build from a directory of markdown/text files
python3 scripts/build-reference-db.py ./my-docs/ -o my-skill.dbMultiple Claude Code sessions each spawn their own MCP server process, all sharing the same SQLite database:
reindex.lock) ensures only one process reindexes at a timebusy_timeout = 5000 gives concurrent readers/writers 5 seconds to acquire locks<uuid>.jsonl) are indexed; agent subagent files are skippedAutomatic indexing is handled three ways:
index_session MCP tool) indexes each session immediately with FTS5; embeddings are filled lazily on next server warmupmemory-reindex) runs every 30 minutes as a catch-all for missed sessionsconversation-backup) rsyncs raw JSONL files every 30 minutes to ~/.claude-memory/conversation-archive/ before Claude Code can prune themManual reindex: npx tsc && node dist/reindex-cli.js
Search memories using hybrid keyword + vector search.
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | (required) | Search query text |
maxResults | number | 10 | Maximum results to return |
minScore | number | 0 | Minimum relevance score (0-1) |
after | string | "" | Only results after this date (YYYY-MM-DD) |
before | string | "" | Only results before this date (YYYY-MM-DD) |
project | string | "" | Filter by project directory name |
source | string | "" | "curated", "conversations", "codebase", or "" for all |
2-pass multi-hop search with entity expansion. Same parameters as memory_search. Pass 1 runs standard hybrid search. Pass 2 extracts entities (tools, projects, people) from top results and searches for those entities via keyword + entity overlap (skips vector + temporal to save ~500ms).
Search indexed codebases for existing implementations.
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | (required) | Search query (e.g., "manifest discovery") |
codebase | string | "" | Filter to a specific codebase name, or "" for all |
maxResults | number | 10 | Maximum results to return |
Find symbol definitions (classes, functions, methods) across indexed codebases.
| Parameter | Type | Default | Description |
|---|---|---|---|
pattern | string | (required) | SQL LIKE pattern (e.g., "%PaymentService%") |
codebase | string | "" | Filter to a specific codebase |
kind | string | "" | Filter by symbol kind: "class", "function", "method", etc. |
Walk the call graph upstream (callers) or downstream (callees) from a file.
| Parameter | Type | Default | Description |
|---|---|---|---|
file_path | string | (required) | File path within the codebase |
direction | string | "downstream" | "upstream" (callers) or "downstream" (callees) |
depth | number | 1 | Traversal depth (1-3) |
Find the cluster of tightly-coupled files around a given file using Louvain community detection.
| Parameter | Type | Default | Description |
|---|---|---|---|
file_path | string | (required) | File path to find the community for |
Query cross-repo build dependency edges.
| Parameter | Type | Default | Description |
|---|---|---|---|
codebase | string | (required) | Codebase name |
direction | string | "imports" | "imports" (what this repo depends on) or "imported_by" (what depends on this repo) |
List entities extracted from indexed content, ranked by occurrence count.
| Parameter | Type | Default | Description |
|---|---|---|---|
entity_type | string | "" | Filter by type: "tool", "project", "person", or "" for all |
limit | number | 50 | Maximum entities to return |
Explore entity co-occurrence neighborhoods.
| Parameter | Type | Default | Description |
|---|---|---|---|
entity | string | (required) | Entity value to explore |
depth | number | 1 | Neighborhood depth (1-2) |
Read a specific memory file or retrieve a past conversation.
| Parameter | Type | Default | Description |
|---|---|---|---|
path | string | (required) | Relative path within ~/.claude-memory/, or a session UUID |
from_line | number | 1 | Starting line number (1-based) |
lines | number | 0 | Number of lines to return (0 = all) |
Write to memory files with immediate indexing and embedding.
| Parameter | Type | Default | Description |
|---|---|---|---|
content | string | (required) | Content to write |
file | string | "memory/YYYY-MM-DD.md" | Target file (MEMORY.md or memory/*.md) |
append | boolean | true | Append to file or overwrite |
Index a conversation session JSONL file (called by SessionEnd hook).
| Parameter | Type | Default | Description |
|---|---|---|---|
session_path | string | (required) | Absolute path to the session JSONL file |
Health check for both backends. Returns chunk counts, vector counts, model info, quantization status.
A synthetic corpus of 50 documents and 50 queries across four categories measures recall:
| Configuration | R@5 | R@10 |
|---|---|---|
| 2-signal (keyword + vector) | 0.680 | 0.786 |
| 4-signal (+ temporal + entity) | 0.777 | 0.858 |
| Category | 2-signal R@5 | 4-signal R@5 | Delta |
|---|---|---|---|
| entity | 0.896 | 1.000 | +10.4pp |
| general | 0.833 | 0.833 | +0.0pp |
| multi-hop | 0.463 | 0.642 | +17.9pp |
| temporal | 0.563 | 0.655 | +9.2pp |
Run benchmarks: python3 benchmarks/retrieval_bench.py
A built-in diagnostic and repair tool for the search index.
# Diagnose (read-only)
node dist/doctor-cli.js
# Diagnose and repair
node dist/doctor-cli.js --fixChecks: chunk/file/vector row counts, FTS5 integrity, cross-table consistency, WAL size, stale processes, stale locks.
Repairs (with `--fix`): Rebuilds FTS5 and vec0 tables from source data, checkpoints WAL, removes stale locks.
npm install # Install Node.js dependencies
npm run build # Build indexer + doctor CLI (esbuild bundles)
npm run typecheck # TypeScript type checking
npm test # tsc compile + integration tests (node --test)
# Python tests
python3 -m pytest scripts/test_*.py -vMCP Server (Python):
Indexer (Node.js):
Webhook Pipeline (Python):
git showBEGIN IMMEDIATECode Intelligence (Python):
Chunking & Scoring:
MIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.