Rewrite README to showcase plugin functionality

Lead with value prop and install command, add conversation example,
restructure around features/hooks/auto-behaviors, consolidate env
vars and API reference into clean tables, move API server docs below
plugin setup since it's optional.
This commit is contained in:
Viktor Barzin 2026-03-14 14:52:09 +00:00
parent 0d1cff3038
commit be9e6352c3
No known key found for this signature in database
GPG key ID: 0EB088298288D958

462
README.md
View file

@ -1,128 +1,131 @@
# Claude Memory MCP
A persistent memory layer for Claude Code that stores knowledge across sessions. Operates as an MCP (Model Context Protocol) server with optional PostgreSQL API backend, local SQLite cache with background sync, and Vault integration for secrets.
## Quick Install (Claude Code Plugin)
Give Claude persistent memory that survives across sessions, context compactions, and machines.
```bash
claude plugins install github:ViktorBarzin/claude-memory-mcp
# Works immediately with local SQLite (no server needed)
# For multi-device sync, set these env vars:
export MEMORY_API_URL="https://your-server.example.com"
export MEMORY_API_KEY="your-api-key"
```
The plugin provides:
- `/remember <fact>` and `/recall <query>` slash commands
- Auto-recall hook that checks memories before each response
- Auto-learn hook that extracts corrections and preferences after each response
- Compaction survival (memories are re-injected after context compaction)
- Auto-approve for all memory tool calls (no permission prompts)
That's it. Claude now remembers things.
## What It Does
```
You: "remember I prefer Svelte for all new frontend apps"
Claude: Stored. ✓
── 3 weeks later, new session, different machine ──
You: "build me a dashboard for this API"
Claude: I'll set up a SvelteKit project since that's your preference...
```
**No configuration needed** for single-machine use. Memories are stored in a local SQLite database with full-text search. For multi-machine sync, point it at an API server (details below).
## Features
### Slash Commands
- **`/remember <fact>`** — store a fact, preference, decision, or person detail
- **`/recall <query>`** — search memories by topic
### Automatic Behaviors (via hooks)
- **Auto-recall** — before responding, Claude checks stored memories for relevant context (preferences, past corrections, decisions). Completely invisible to the user.
- **Auto-learn** — after each response, a background process analyzes the conversation for corrections, preferences, and decisions worth remembering. Uses haiku-as-judge for conservative extraction.
- **Compaction survival** — when Claude's context window compacts, key memories are saved to a marker file and re-injected on the next prompt. No knowledge is lost.
- **Auto-approve** — memory tool calls are approved automatically, no permission prompts.
### MCP Tools
Claude has direct access to these tools during conversation:
| Tool | Description |
|------|-------------|
| `memory_store` | Store a fact with category, tags, importance, and semantic search keywords |
| `memory_recall` | Search memories using full-text search with expanded query terms |
| `memory_list` | List recent memories, optionally filtered by category |
| `memory_delete` | Delete a memory by ID |
| `secret_get` | Retrieve the decrypted content of a sensitive memory |
### Memory Categories
Memories are organized into: `facts`, `preferences`, `projects`, `people`, `decisions`
### Sensitive Memory Support
Mark memories as sensitive with `force_sensitive: true`. When Vault is configured, sensitive content is encrypted at rest and only decryptable via `secret_get`.
## Architecture
```
MCP Server (per Claude session)
┌─────────────────────────────────────────────┐
│ Tool call (store/recall/list/delete) │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Local SQLite │◄──│ SyncEngine │ │
│ │ (cache+FTS5) │ │ (background │ │
│ │ always used │ │ thread, 60s) │ │
│ └─────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌──────────────┐ │ │
│ │ pending_ops │────────────┘ │
│ │ (offline │ push queued writes │
│ │ write queue)│ pull server changes │
│ └──────────────┘ │
└──────────────────────────────────────────────┘
┌──────────▼───────────┐
│ API Server (k8s) │
│ 2 replicas + PDB │
│ pod anti-affinity │
└──────────┬───────────┘
┌──────────▼───────────┐
│ PostgreSQL │
│ (authoritative) │
└──────────────────────┘
Claude Code Session
┌──────────────────────────────────────────────────────┐
│ Hooks MCP Server │
│ ┌──────────────────┐ ┌────────────────────┐ │
│ │ auto-recall │───────▶│ memory_store │ │
│ │ auto-learn │ │ memory_recall │ │
│ │ compaction │ │ memory_list │ │
│ │ auto-approve │ │ memory_delete │ │
│ └──────────────────┘ │ secret_get │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌─────────────────────────┼──────────┐ │
│ │ Local SQLite │ │ │
│ │ (cache + FTS5) SyncEngine │ │
│ │ ◄──── always ────(background, 60s) │ │
│ │ used push queued writes │ │
│ │ pull server changes│ │
│ │ pending_ops ──────────┘ │ │
│ │ (offline write queue) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
optional, for multi-machine sync
┌──────────▼───────────┐
│ API Server (FastAPI) │
│ Docker / Kubernetes │
└──────────┬───────────┘
┌──────────▼───────────┐
│ PostgreSQL │
│ (authoritative) │
└──────────────────────┘
```
In **hybrid mode** (the default when an API key is set), all reads hit local SQLite for instant results. Writes go to SQLite first, then attempt a synchronous API push — if the API is down, writes queue in a `pending_ops` table and sync on the next background cycle. The server is authoritative (server-wins conflict resolution).
## Operating Modes
| Mode | Condition | Storage | Use Case |
|------|-----------|---------|----------|
| **SQLite-only** | No `MEMORY_API_KEY` | SQLite + FTS5 | Single user, local Claude Code |
| **Hybrid** (default) | `MEMORY_API_KEY` set | Local SQLite cache + API sync | Multi-session with offline resilience |
| **HTTP-only** (legacy) | `MEMORY_API_KEY` + `MEMORY_SYNC_DISABLE=1` | PostgreSQL via HTTP API | Direct API, no local cache |
| **Full** | Any mode + Vault configured | Above + Vault for secrets | Multi-user, team deployment |
| Mode | When | What happens |
|------|------|--------------|
| **SQLite-only** | No env vars set | Everything local. Zero config. Works offline. |
| **Hybrid** | `MEMORY_API_KEY` set | Local SQLite for reads + background sync to API. Writes queue if API is down. |
| **HTTP-only** | `MEMORY_API_KEY` + `MEMORY_SYNC_DISABLE=1` | Direct API calls, no local cache. Legacy mode. |
| **Full** | Any mode + Vault configured | Above + Vault for encrypting sensitive memories at rest. |
## Setting Up a New Agent
## Setup
### 1. Install the package
### Option 1: Plugin Install (recommended)
```bash
pip install claude-memory-mcp
claude plugins install github:ViktorBarzin/claude-memory-mcp
```
Or install from source for development:
Works immediately with SQLite-only mode. To enable multi-machine sync:
```bash
git clone https://github.com/ViktorBarzin/claude-memory-mcp.git
cd claude-memory-mcp
pip install -e .
export MEMORY_API_URL="https://your-server.example.com"
export MEMORY_API_KEY="your-api-key"
```
### 2. Choose your mode and configure
### Option 2: Manual MCP Config
#### Local Mode (SQLite, zero config)
No server needed. Memories are stored in a local SQLite database.
Add to your Claude Code MCP settings (`~/.claude/settings.json` or project `.claude/settings.json`):
Add to `~/.claude/settings.json`:
```json
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "python3",
"args": ["-m", "claude_memory.mcp_server"]
}
}
}
```
The database defaults to `~/.claude/claude-memory/memory/memory.db`. Override with:
```json
{
"env": {
"MEMORY_HOME": "/path/to/memory/dir"
}
}
```
#### Hybrid Mode (recommended for shared deployments)
Point the MCP server at a running API instance. Memories are cached locally in SQLite for fast reads and offline resilience, and synced to the API in the background.
```json
{
"mcpServers": {
"memory": {
"claude_memory": {
"type": "stdio",
"command": "python3",
"args": ["-m", "claude_memory.mcp_server"],
"env": {
"MEMORY_API_URL": "https://claude-memory.example.com",
"MEMORY_API_URL": "https://your-server.example.com",
"MEMORY_API_KEY": "your-api-key"
}
}
@ -130,60 +133,27 @@ Point the MCP server at a running API instance. Memories are cached locally in S
}
```
To disable local caching and use direct HTTP (legacy behavior), add `"MEMORY_SYNC_DISABLE": "1"` to `env`.
Omit the `env` block for SQLite-only mode. Requires `pip install claude-memory-mcp`.
#### Full Mode (with Vault for secrets)
Same as Server Mode but with Vault for automatic credential detection and secure storage:
```json
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "python3",
"args": ["-m", "claude_memory.mcp_server"],
"env": {
"MEMORY_API_URL": "https://claude-memory.example.com",
"MEMORY_API_KEY": "your-api-key",
"VAULT_ADDR": "https://vault.example.com",
"VAULT_TOKEN": "your-vault-token"
}
}
}
}
```
### 3. Verify it works
Start a Claude Code session and test:
### Verify
```
> Store a test memory: "Claude Memory MCP is working"
> Recall memories about "Claude Memory"
You: /remember "I prefer dark mode in all applications"
You: /recall "UI preferences"
```
You should see the MCP tools `memory_store`, `memory_recall`, `memory_list`, `memory_delete`, and `secret_get` available.
### Environment Variable Aliases
For backward compatibility, these aliases are supported:
| Primary | Alias |
|---------|-------|
| `MEMORY_API_URL` | `CLAUDE_MEMORY_API_URL` |
| `MEMORY_API_KEY` | `CLAUDE_MEMORY_API_KEY` |
## Running the API Server
### Docker Compose (recommended)
Only needed for multi-machine sync. Skip this if you're using SQLite-only mode.
### Docker Compose
```bash
cd docker
docker compose up -d
```
This starts the API + PostgreSQL. Vault is available as an optional profile:
Starts the API server + PostgreSQL. Optionally add Vault:
```bash
docker compose --profile vault up -d
@ -193,145 +163,15 @@ docker compose --profile vault up -d
```bash
pip install claude-memory-mcp[api]
export DATABASE_URL="postgresql://user:pass@localhost:5432/claude_memory"
export API_KEY="your-secret-key"
# Run migrations
alembic upgrade head
# Start server
uvicorn claude_memory.api.app:app --host 0.0.0.0 --port 8000
```
### Environment Variables
### Kubernetes
| Variable | Description | Default |
|----------|-------------|---------|
| `DATABASE_URL` | PostgreSQL connection string | Required |
| `API_KEY` | Single-user API key | None |
| `API_KEYS` | Multi-user JSON map `{"user": "key"}` | None |
| `VAULT_ADDR` | Vault server address | None |
| `VAULT_TOKEN` | Vault authentication token | None |
| `MEMORY_ENCRYPTION_KEY` | AES-256 key (hex or passphrase) for non-Vault encryption | None |
| `MEMORY_SYNC_INTERVAL` | Seconds between background sync cycles (hybrid mode) | `60` |
| `MEMORY_SYNC_DISABLE` | Set to `1` to disable local cache and sync (HTTP-only mode) | None |
## Multi-User Setup
For team deployments, use `API_KEYS` with a JSON mapping:
```bash
export API_KEYS='{"alice": "key-alice-xxx", "bob": "key-bob-yyy"}'
```
Each user gets isolated memory storage — users cannot see each other's memories. Each agent/user gets their own API key in their MCP config.
### Adding a new user
1. Generate a key: `openssl rand -base64 32`
2. Add to `API_KEYS`: `{"existing": "...", "newuser": "generated-key"}`
3. Restart the API server
4. Give the new user their MCP config with their key
## MCP Tools
| Tool | Description |
|------|-------------|
| `memory_store` | Store a fact with category, tags, importance, and expanded keywords |
| `memory_recall` | Search memories using full-text search with expanded query terms |
| `memory_list` | List recent memories, optionally filtered by category |
| `memory_delete` | Delete a memory by ID |
| `secret_get` | Retrieve the actual content of a sensitive/redacted memory |
## API Reference
### Health Check
```
GET /health
```
### Store Memory
```
POST /api/memories
Authorization: Bearer <api-key>
{"content": "...", "category": "facts", "tags": "tag1,tag2", "expanded_keywords": "related terms", "importance": 0.8}
```
### Recall Memories
```
POST /api/memories/recall
Authorization: Bearer <api-key>
{"context": "search terms", "expanded_query": "additional search terms", "category": "facts", "limit": 10}
```
### List Memories
```
GET /api/memories?category=facts&limit=20
Authorization: Bearer <api-key>
```
### Delete Memory (soft delete)
```
DELETE /api/memories/{id}
Authorization: Bearer <api-key>
```
Sets `deleted_at` on the record rather than removing it, so sync clients can detect deletions.
### Sync Memories
```
GET /api/memories/sync?since=2026-03-14T10:00:00+00:00
Authorization: Bearer <api-key>
```
Returns all memories changed since the given timestamp (including soft-deleted ones). Without `since`, returns a full dump of non-deleted memories. Used by the SyncEngine for incremental sync.
### Get Secret Content
```
POST /api/memories/{id}/secret
Authorization: Bearer <api-key>
```
### Migrate Existing Secrets
```
POST /api/memories/migrate-secrets
Authorization: Bearer <api-key>
```
### Bulk Import
```
POST /api/memories/import
Authorization: Bearer <api-key>
[{"content": "...", "category": "facts"}, ...]
```
## Database Migrations
This project uses Alembic for database migrations. Migrations run automatically on API server startup.
To run manually:
```bash
export DATABASE_URL="postgresql://user:pass@localhost:5432/claude_memory"
alembic upgrade head
```
To create a new migration:
```bash
alembic revision -m "description of change"
```
## Kubernetes Deployment
The API server is designed for high availability:
- **2 replicas** with pod anti-affinity (spread across nodes)
- **PodDisruptionBudget** (`min_available: 1`) prevents both pods going down during voluntary disruptions
- **Startup probe** gives 60s for initial DB connection before the pod is killed
### Helm
Designed for high availability: 2 replicas with pod anti-affinity, PodDisruptionBudget, and startup probes.
```bash
helm install claude-memory deploy/helm/claude-memory \
@ -340,7 +180,7 @@ helm install claude-memory deploy/helm/claude-memory \
--set ingress.host="claude-memory.yourdomain.com"
```
### Raw Manifests
Or raw manifests:
```bash
kubectl apply -f deploy/kubernetes/namespace.yaml
@ -351,24 +191,92 @@ kubectl create secret generic claude-memory-secrets \
kubectl apply -f deploy/kubernetes/
```
## Multi-User Setup
For team deployments, use `API_KEYS` with a JSON mapping:
```bash
export API_KEYS='{"alice": "key-alice-xxx", "bob": "key-bob-yyy"}'
```
Each user gets isolated memory storage. Users cannot see each other's memories.
**Adding a user:**
1. Generate a key: `openssl rand -base64 32`
2. Add to `API_KEYS` JSON
3. Restart the API server
4. Share the key with the user
## Plugin Hooks
When installed as a Claude Code plugin, these hooks run automatically:
| Hook | Event | Description |
| Hook | Event | What it does |
|------|-------|-------------|
| `pre-compact-backup.sh` | PreCompact | Saves top 20 memories to a marker file before context compaction |
| `post-compact-recovery.sh` | UserPromptSubmit | Detects compaction marker and injects recovery context (one-time) |
| `user-prompt-recall.py` | UserPromptSubmit | Instructs Claude to call `memory_recall` before responding |
| `auto-learn.py` | Stop (async) | Uses haiku-as-judge to extract corrections/preferences from the conversation |
| `auto-allow-memory-tools.py` | PermissionRequest | Auto-approves all memory MCP tool calls without prompting |
| `post-compact-recovery.sh` | UserPromptSubmit | Re-injects saved memories after compaction (one-time, then deletes marker) |
| `user-prompt-recall.py` | UserPromptSubmit | Tells Claude to check `memory_recall` before responding to each message |
| `auto-learn.py` | Stop (async) | Runs haiku-as-judge on the last exchange to extract durable facts worth storing |
| `auto-allow-memory-tools.py` | PermissionRequest | Auto-approves `memory_store`, `memory_recall`, `memory_list`, `memory_delete`, `secret_get` |
### Debug Environment Variables
### Debug
| Variable | Effect |
|----------|--------|
| `DEBUG_CLAUDE_MEMORY_HOOKS=1` | Enable debug logging to stderr for all hooks |
| `DISABLE_CLAUDE_MEMORY_AUTO_APPROVE=1` | Disable auto-approve (prompts for each tool call) |
```bash
# See what hooks are doing
export DEBUG_CLAUDE_MEMORY_HOOKS=1
# Disable auto-approve to see permission prompts
export DISABLE_CLAUDE_MEMORY_AUTO_APPROVE=1
```
## API Reference
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Health check |
| `/api/memories` | POST | Store a memory |
| `/api/memories` | GET | List memories (`?category=facts&limit=20`) |
| `/api/memories/recall` | POST | Search memories by context and expanded query |
| `/api/memories/{id}` | DELETE | Soft-delete a memory |
| `/api/memories/sync` | GET | Incremental sync (`?since=ISO-timestamp`) |
| `/api/memories/{id}/secret` | POST | Get decrypted sensitive memory content |
| `/api/memories/migrate-secrets` | POST | Re-encrypt existing secrets with current Vault config |
| `/api/memories/import` | POST | Bulk import memories (JSON array) |
All endpoints except `/health` require `Authorization: Bearer <api-key>`.
## Environment Variables
### MCP Server (client-side)
| Variable | Description | Default |
|----------|-------------|---------|
| `MEMORY_API_URL` | API server URL | `http://localhost:8080` |
| `MEMORY_API_KEY` | API key (enables hybrid mode) | None |
| `MEMORY_HOME` | Local storage directory | `~/.claude/claude-memory` |
| `MEMORY_DB` | SQLite database path override | `$MEMORY_HOME/memory/memory.db` |
| `MEMORY_SYNC_INTERVAL` | Background sync interval in seconds | `60` |
| `MEMORY_SYNC_DISABLE` | Set to `1` for HTTP-only mode | None |
Aliases `CLAUDE_MEMORY_API_URL` and `CLAUDE_MEMORY_API_KEY` are also supported.
### API Server
| Variable | Description | Default |
|----------|-------------|---------|
| `DATABASE_URL` | PostgreSQL connection string | Required |
| `API_KEY` | Single-user API key | None |
| `API_KEYS` | Multi-user JSON map `{"user": "key"}` | None |
| `VAULT_ADDR` | Vault server address | None |
| `VAULT_TOKEN` | Vault authentication token | None |
| `MEMORY_ENCRYPTION_KEY` | AES-256 key for non-Vault encryption | None |
## Database Migrations
Migrations run automatically on API server startup. To run manually:
```bash
export DATABASE_URL="postgresql://user:pass@localhost:5432/claude_memory"
alembic upgrade head
```
## Development