claude-memory
README.md
# claude-memory
Memory + project tracking for Claude Code. One MCP server.
- Semantic search over **all past Claude Code transcripts** — new sessions recall old ones, way past the context window
- Durable notes (`remember`) — per-project or global
- Structured tracking: projects → milestones → epics → tickets → todos, rendered as roadmap
- Tracking items embedded into same vector space — tickets show up in semantic search
- Per-project system prompts, stored in DB, injectable at session start
Stack: **Voyage AI** embeddings + **Qdrant** vector DB + **SQLite** + **FastMCP**.
All free: Voyage free tier easily covers personal use, Qdrant Cloud free tier holds 1M vectors (or run local docker). $0 to operate.
## Setup
Two keys:
- Voyage → <https://dashboard.voyageai.com>
- Qdrant → free cluster at <https://cloud.qdrant.io>, or `docker run -p 6333:6333 qdrant/qdrant`
```sh
git clone https://github.com/mathis-sperlich/claude-memory
cd claude-memory
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env
# fill VOYAGE_API_KEY, QDRANT_URL, QDRANT_API_KEY
```
Point `SCAN_PROJECTS` in `ingest.py` at your transcript dirs (Claude Code writes them to `~/.claude/projects/<encoded-project-dir>/*.jsonl`).
## Ingest
```sh
.venv/bin/python ingest.py --dry-run # sanity-check chunking
.venv/bin/python ingest.py # embed + upsert
```
Idempotent — re-runs only embed new chunks. Safe as cron job. Hourly launchd template: `launchd/com.mathis.claude-memory.plist` (edit paths, `cp` to `~/Library/LaunchAgents/`, `launchctl load`).
Test retrieval from CLI:
```sh
.venv/bin/python query.py "how did the auth token refresh bug get fixed?"
```
Bad results? Lower `MAX_CHUNK_CHARS` in `ingest.py`, or try bigger `EMBED_MODEL` in `.env` and re-ingest with `--reset`.
## Wire into Claude Code
`~/.claude/settings.json`:
```json
{
"mcpServers": {
"claude-memory": {
"command": "/path/to/claude-memory/.venv/bin/python",
"args": ["/path/to/claude-memory/mcp_server.py"]
}
}
}
```
Restart Claude Code. Done — Claude now has `query_history`, `remember`, tracking tools, system-prompt tools.
## Tools
### Memory
| Tool | Purpose |
|---|---|
| `query_history(question, k=, project=, since=, kind=)` | Semantic search over everything. `kind`: `note`, `transcript`, `tracking`, or subtype |
| `list_recent_sessions(days=, project=)` | What was I working on lately |
| `remember(content, title=, tags=, project=)` | Save durable note. `project` scopes it; omit → global (surfaces in every project's search) |
| `list_notes(tag=, limit=)` / `forget(note_id)` | Manage notes |
### Tracking
Hierarchy: project → milestone (optional) → epic → ticket → todo.
| Tool | Purpose |
|---|---|
| `create_project(name, description=)` | Top of hierarchy |
| `create_milestone(project, name, body=, target_date=)` | What ships together |
| `create_epic(project, title, body=, milestone=, priority=)` | Group tickets toward goal |
| `create_ticket(project, title, body=, epic=, priority=)` | Unit of work |
| `create_todo(project, title, body=, ticket=, priority=)` | Small step |
| `list_items(kind=, project=, status=, parent_id=)` | Filtered list |
| `get_item(id)` | One item + children |
| `update_item(id, status=, title=, body=, priority=, ...)` | Partial update, errors on fields that don't apply |
| `delete_item(id)` | Delete. Projects must be empty first |
| `get_roadmap(project)` | Markdown roadmap: milestones → epics → tickets + progress |
| `list_projects()` | Every project name across all stores |
`status`: `open` / `in_progress` / `done`. `priority`: `P0`–`P3`.
### System prompts
`set_system_prompt(content, project=)` / `get_system_prompt(project=)` / `list_system_prompts()` / `delete_system_prompt(project=)`. Global + per-project layers, composed on read. Stored in `tracking.db`. Falls back to `docs/usage.md` when unset.
## Hooks (optional, deterministic)
MCP tools fire when model decides. Hooks fire always. `hooks/session_start.py` injects current project's open tickets + system prompt at every session start:
```json
{
"hooks": {
"SessionStart": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "/path/to/claude-memory/.venv/bin/python /path/to/claude-memory/hooks/session_start.py"
}]
}]
}
}
```
## Remote access (optional)
Default = local stdio, zero network. Want same memory from claude.ai or other machines? HTTP transport + Cloudflare tunnel + GitHub OAuth with login allowlist:
```sh
.venv/bin/python mcp_server.py --transport http --port 8765
```
Full walkthrough incl. launchd services + self-healing watchdog: [CLOUD_SETUP.md](CLOUD_SETUP.md).
## Notes
- Privacy: Voyage sees text at embed time (no training on customer data per TOS), Qdrant Cloud stores vectors + payloads. Both concern you → local Qdrant + local embedder, same code.
- Stalled embed requests bounded by `VOYAGE_TIMEOUT` / `VOYAGE_MAX_RETRIES` env vars (default 20s / 2).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues