Ultrafast local MCP memory for LLMs — project-aware, zero-config
Project description
sage-memory
Persistent wisdom. Structured thought
Memory that learns. Not just remembers.
sage-memory is a local MCP memory server for AI agents. It gives any AI assistant — coding tools, personal agents, team copilots — three kinds of persistent memory that compound over time:
-
Knowledge — what you understand. Architecture, conventions, preferences, domain logic. (→ memory skill)
-
Structure — how things connect. Entity relationships, dependency graphs, ownership. (→ ontology skill)
-
Experience — what you've learned the hard way. Mistakes, corrections, prevention rules. (→ self-learning skill)
One search returns all three. The agent knows how things work, how they connect, and what to watch out for — the way a human expert thinks about a domain.
memory skill ontology skill self-learning skill
│ │ │
▼ ▼ ▼
┌─────────┐ ┌────────────┐ ┌────────────┐
│Knowledge│ │ Structure │ │ Experience │
│ (prose) │ │ (graph) │ │ (rules) │
└────┬────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
└──────────────────┼─────────────────────┘
▼
┌───────────────────┐
│ sage-memory │
│ one SQLite file │
│ FTS5 + vec + edges│
└────────┬──────────┘
│
▼
unified search
"what do I know about X?"
→ knowledge + structure + experience
Why sage-memory
- The agent gets better every session. Mistakes become prevention rules. Prevention rules compound across projects. The agent develops judgment, not just a bigger database.
- Intelligence lives in skills, not in the server. The server is fast and dumb. Three skills teach the agent what to remember, how to learn from errors, and when to recall. Improve the agent by editing a markdown file, not shipping code.
- Zero infrastructure. One SQLite file. No Docker, no Redis, no cloud, no API keys. Your knowledge never leaves your machine.
Highlights
- 97.2% recall@5 on LongMemEval-S, zero API cost (pure FTS5+RRF). Add an embedder key and it goes to 98.6% — beating gbrain (0.976) at ~$0.50 per 500q. Full report · Reproducer
- 91% recall on natural language queries — proven on 4 real codebases (340K lines)
- Sub-3ms search, sub-0.3ms graph traversal, ~1,000 writes/sec
- Self-learning loop — mistake → prevention rule → recall → improvement, automatically
- Graph-native — typed edges with cycle-safe multi-hop traversal
- Six-stage retrieval pipeline with chunking, query expansion, and rerank — all optional, all opt-in via API key
- Lean — 4 runtime dependencies, no ML stack required for the free path
Setup
With uv, sage-memory installs and runs automatically — no manual pip install:
Don't have uv? One command:
curl -LsSf https://astral.sh/uv/install.sh | sh(full guide)
Claude Code
{
"mcpServers": {
"sage-memory": {
"command": "uvx",
"args": ["sage-memory"]
}
}
}
Cursor
In .cursor/mcp.json:
{
"mcpServers": {
"sage-memory": {
"command": "uvx",
"args": ["sage-memory"]
}
}
}
Alternative: install with pip
pip install sage-memory
Use "command": "sage-memory" instead of uvx in your MCP config.
For neural embeddings: pip install sage-memory[neural]
How It Works
Two databases, automatic routing
Each context gets its own database. Cross-context knowledge lives separately. Search hits both; context results rank higher.
~/code/billing-service/
.sage-memory/memory.db ← this project's knowledge
~/.sage-memory/memory.db ← cross-project patterns
Call sage_memory_set_project at session start to tell sage-memory which project you're working on. This ensures stores and searches hit the correct database — especially important when the MCP server stays running across project switches. Without it, sage-memory falls back to detecting the project from the server's working directory.
Search
FTS5 BM25 with OR semantics — documents matching more query terms rank higher. AND-based alternatives require every term to match, returning nothing for natural language queries. This single decision gives sage-memory 91% recall where AND-based systems achieve 20%.
filter_tags applies a hard AND filter before ranking — use for namespace isolation (e.g., filter_tags: ["self-learning"] returns only learnings). tags applies a soft boost without excluding.
Graph
Typed directed edges between memories via sage_memory_link. Cycle-safe multi-hop traversal via sage_memory_graph. One graph call replaces N sequential searches for dependency chains, blocking relationships, or ownership trees.
Self-learning loop
Tools
| Tool | Purpose |
|---|---|
sage_memory_set_project |
Set active project for this session — call first |
sage_memory_store |
Persist knowledge with SHA-256 auto-dedup |
sage_memory_search |
BM25 search with filter_tags (hard) and tags (soft boost) |
sage_memory_update |
Partial update by ID, auto re-index |
sage_memory_delete |
Delete by ID — CASCADE removes connected edges |
sage_memory_list |
Browse with AND tag filtering |
sage_memory_link |
Create/delete typed directed edges |
sage_memory_graph |
Cycle-safe multi-hop traversal |
Tool examples
Set project context (call first):
{
"path": "/home/user/code/billing-service"
}
Store:
{
"content": "The billing service uses saga pattern. PaymentOrchestrator coordinates StripeGateway, LedgerService, NotificationService.",
"title": "Payment saga orchestration via PaymentOrchestrator",
"tags": ["billing", "saga", "architecture"],
"scope": "project"
}
Search with namespace isolation:
{
"query": "payment failure handling",
"filter_tags": ["self-learning"],
"limit": 5
}
Link two memories:
{
"source_id": "abc123",
"target_id": "def456",
"relation": "depends_on",
"properties": {"confidence": 0.9}
}
Traverse dependencies (2 hops):
{
"id": "abc123",
"relation": "depends_on",
"direction": "outbound",
"depth": 2
}
Skills
Three built-in skills, one for each kind of memory. Each works with MCP (full capability) or filesystem fallback (reduced but functional).
memory → Knowledge
Three layers: automatic recall at session start, automatic remember during work, deliberate capture via sage learn with dependency graph building and knowledge reports.
ontology → Structure
Typed knowledge graph. Entities (Task, Person, Project, Event, Document) as memories. Relationships as graph edges via sage_memory_link. Validation rules, cardinality constraints, cycle detection.
self-learning → Experience
Closed-loop mistake detection. Five types: gotcha, correction, convention, api-drift, error-fix. Every learning has a four-part structure: what happened, why wrong, what's correct, prevention rule. Promotion ladder: context → personal → team scope.
Learnings link to ontology entities, enabling graph-based targeted recall: "show me all past mistakes connected to this task."
Installing skills into your agent
The three skills ship inside the wheel. Install them into your AI agent of choice:
# Claude Code (this project only)
sage-memory install-skills claude-code --project
# Cursor (user-wide, all projects)
sage-memory install-skills cursor --global
# Every supported agent at once
sage-memory install-skills all --project
Supported agents: Claude Code, Cursor, Codex CLI, Gemini CLI, OpenCode. Each gets its native skill format — directory of SKILL.md files for Claude Code, .mdc rules for Cursor, marker-delimited blocks in AGENTS.md / GEMINI.md for the others. Re-installs are idempotent; modified files trigger a diff prompt. Use --dry-run to preview, -y to auto-overwrite (required in non-TTY environments like CI).
Use Cases
Coding assistants — learn your codebase, conventions, and past debugging insights. Build architecture graphs during code exploration. Avoid repeating the same mistakes across sessions. This is where sage-memory has the deepest benchmarks and proven skills.
Personal agents — learn user preferences, remember relationships between people and places, avoid repeating rejected suggestions. An agent that remembers "user is vegetarian, allergic to nuts" and never suggests incompatible options again.
Team copilots — learnings promoted from personal to team scope mean everyone benefits from each member's corrections. Organizational knowledge accumulates without manual documentation.
Performance
| Memories | Store | Search mean | Search P95 | Recall |
|---|---|---|---|---|
| 1,000 | 1.0ms | 2.5ms | 9ms | 80% |
| 5,000 | 0.9ms | 12ms | 56ms | 81% |
| 10,000 | 0.9ms | 21ms | 72ms | 83% |
| 22,000 | 1.0ms | 46ms | 101ms | 83% |
Graph: 0.19ms P50 edge creation, 0.17ms P50 traversal. 49 tests, all passing.
On LLM-authored content (the real use case): 91% overall recall — 100% on API lookups, workflow, and architecture queries.
LongMemEval-S — Benchmark
| Config | R@1 | R@3 | R@5 | R@10 | API cost |
|---|---|---|---|---|---|
| Free-path (FTS5 + RRF, LocalEmbedder 384d) | 0.834 | 0.952 | 0.972 | 0.986 | $0 |
| Hosted-vector (FTS5 + RRF + OpenAI 1536d) | 0.886 | 0.970 | 0.986 | 0.992 | ~$0.50 per 500q |
| Hosted-vector Δ over free-path | +5.2pp | +1.8pp | +1.4pp | +0.6pp |
- Free-path 97.2% R@5 is the headline number for users with no embedder API key. Pure FTS5 BM25 + chunk-level RRF fusion, 384d local embeddings used only for the vector channel (which contributes little to R@5 on this dataset). No LLM calls in the retrieval path.
- Hosted-vector 98.6% R@5 demonstrates the ADR-005 cascade is doing real work when a hosted embedder is configured. The +1.4pp lift comes mostly from semantic question types (single-session-preference, temporal-reasoning).
Optional: Neural Embeddings
Default uses a zero-dependency local embedder. For higher semantic recall:
pip install sage-memory[neural]
Auto-detected, enables hybrid search (FTS5 + vector via Reciprocal Rank Fusion).
Retrieval Pipeline
Sage Memory's search is a six-stage pipeline combining three retrieval channels under a single weighted Reciprocal Rank Fusion (RRF) score. The design and acceptance criteria are spelled out in the architecture decision records.
The three channels:
bm25— FTS5 full-text search over titles + content + tags. Always-on; the load-bearing channel for keyword recall.vector— sqlite-vec cosine similarity. Skipped when no hosted embedder is configured AND the local 384d embedder's quality falls below the vector-search threshold.graph— entity-mediated proximity. Two-layer BFS over auto- extracted entity mentions + manual edges; contributes when an LLM key is configured and the worker has populated the entity graph. The default channel weight is 0.7.
The six stages (per call, in order):
- expand — optional LLM query expansion produces
{lex, vec, hyde}variants. A strong-signal short-circuit on the FTS5 bm25 score skips the LLM call when the top hit is confident. - retrieve — per-channel candidate fetch. Lex variants extend the bm25 channel; vec/hyde extend the vector channel.
- fuse — weighted RRF across the three channels collapses to a single ranked list.
- dedup — chunk-to-memory rollup. Chunks live in the schema shipped; chunk hits are folded back into their parent memory.
- rerank — optional LLM rerank on the top-K candidates with a
position-blend curve
[0.75, 0.6, 0.4]over positions[1-3, 4-10, 11+]. - score — tag boost, recency tiebreaker, project-vs-global priority. Final ordering returned to the caller.
Background machinery:
- The extraction worker processes writes asynchronously, populating entities, mentions, and
relations for the graph channel. It also handles
reembedtasks (used bysage-memory reindex) anddeduptasks (LLM-confirmed entity merging). - The embedder cascade resolves a corpus-locked embedder tier at startup. Switching
tiers requires
sage-memory reindex --re-embed --embedder <name>to atomically swapmemories_vec+chunks_vecand queue reembed tasks.
Free-path floor: every LLM-gated feature (expand, rerank, entity extraction, dedup) degrades silently when no LLM key is configured. Search continues to work; the graph channel returns empty and falls out of the RRF; expand/rerank are no-ops. This preserves the zero-config promise — install, store, search.
Architecture
src/sage_memory/ ~7,000 lines · 4 deps (mcp, sqlite-vec, httpx, pyyaml)
Server
├── server.py MCP server: 8 tools, dict dispatch
└── __main__.py CLI entry
Storage + DB
├── db.py Project detection, dual DB, migration runner
├── store.py Memory CRUD (store, update, delete, list)
├── graph.py Edge management, cycle-safe traversal
└── migrations/ 8 SQL migrations: memories + FTS5 + vec0,
edges, health, chunks, entities,
embedding metadata, extraction queue,
worker state
Retrieval pipeline (six stages: expand → retrieve → fuse →
dedup → rerank → score)
├── search.py Dual-DB orchestration, BM25 + RRF, scoring
├── expand.py LLM query expansion (optional)
├── rerank.py LLM rerank with position blend (optional)
├── graph_channel.py Entity-mediated BFS — third RRF channel
└── chunker.py Paragraph/sentence-aware splitter
Embedder cascade
└── embedder.py Local + FastEmbed + OpenAI + Voyage + Cohere
Background worker + LLM
├── worker.py Polling loop, at-most-one task contract
├── extractor.py LLM entity/relation extraction
├── llm.py Provider cascade with retry
├── dedup.py LLM-confirmed memory deduplication
└── config.py 3-layer config cascade (call > env > yaml > built-in)
CLI (sage-memory <subcommand>)
├── cli_status.py status
├── cli_worker.py worker
├── cli_reindex.py reindex (--re-embed, --embeddings, ...)
├── cli_dedup.py dedup (async / --sync)
└── cli_queue.py queue prune
skills/ 3 built-in skills (usable independently)
├── memory/ Knowledge persistence + capture
├── ontology/ Typed knowledge graph
└── self-learning/ Mistake detection + prevention rules
Development
git clone https://github.com/xoai/sage-memory.git
cd sage-memory
pip install -e ".[dev]"
PYTHONPATH=src python tests/test_all.py
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sage_memory-0.8.0.tar.gz.
File metadata
- Download URL: sage_memory-0.8.0.tar.gz
- Upload date:
- Size: 360.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99886a990f93af3f7391f51a8d197fb79a300ef2c85395ad4cc3bc233ccb95be
|
|
| MD5 |
016d91a29278fed1b21e52b97a2f8121
|
|
| BLAKE2b-256 |
040fdec9717fc47de39c2a060721a6fde9ed4194c6d51890bbf3006596bdae20
|
File details
Details for the file sage_memory-0.8.0-py3-none-any.whl.
File metadata
- Download URL: sage_memory-0.8.0-py3-none-any.whl
- Upload date:
- Size: 161.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0666689ac62017ca818a61e80975cf0b0d03bacd5e228fa7498cb3bdad7b255f
|
|
| MD5 |
2355cee7b46f564a866a314d31c75479
|
|
| BLAKE2b-256 |
4eec9be8612d9b8187f2fa83abfc757ecd3475eb1cbeef35ce206bc7ee8cbdc6
|