memento
by UmoLab
README.md
# memento
> Persistent memory for AI coding agents. Local-first. Zero cloud. Plug-and-play with Claude Code via MCP.
[](https://github.com/UmoLab/memento/actions)
[](https://github.com/UmoLab/memento/actions)
[](https://github.com/UmoLab/memento/actions)
[](https://pypi.org/project/memento-memory/)
[](https://github.com/UmoLab/memento/blob/main/LICENSE)
[](https://modelcontextprotocol.io/)
**Stop losing context between sessions.** `memento` gives your AI agent a long-term brain that runs entirely on your laptop. Stored facts (preferences, decisions, conventions) survive across sessions and are recalled by semantic similarity — so the next time you ask Claude to "use my dark theme," it remembers without you re-explaining.
Built for [Claude Code](https://claude.ai/code) but works with any [MCP](https://modelcontextprotocol.io/)-compatible client.
---
## Why
Every Claude Code session starts cold. You re-explain your preferences, your project's conventions, your architecture decisions. After 50 sessions, you've typed the same context thousands of times.
`memento` solves this with persistent memory:
- **Stored automatically** by your agent via MCP tools (`memento_store`, `memento_recall`, etc.)
- **Recalled by semantic similarity** (vector search, no exact-key matching)
- **Survives sessions, restarts, machines** (single SQLite file)
- **100% local** — no API calls, no telemetry, no cloud lock-in
- **Battle-tested** — 179 tests, 92% coverage (with branch tracking), real concurrency tests
---
## 30-second quickstart
### 1. Install
```bash
pip install memento
```
(First run downloads a ~80MB embedding model — one-time, then cached.)
### 2. Initialize the database
```bash
memento init
```
Creates `~/.local/share/memento/memory.db`.
### 3. Wire into Claude Code
Add to `~/.claude/mcp_servers.json` (or `.mcp.json` in your project):
```json
{
"mcpServers": {
"memory": {
"command": "memento",
"args": ["start"],
"env": {"MEMENTO_PATH": "~/.local/share/memento/memory.db"}
}
}
}
```
### 4. Use it
Open Claude Code. It now has access to:
- `store` — save a fact (preference, decision, convention)
- `recall` — semantic search across stored facts
- `update` / `forget` — mutate stored facts
- `recent` / `browse` — inspect what's stored
Tell Claude: *"Remember that I prefer dark mode in all my projects."* Next session, it'll know.
---
## First day with memento
A 5-minute walkthrough to prove the round-trip works:
```bash
$ memento init
Initialized memento at ~/.local/share/memento/memory.db
$ memento list
No memories yet. Run `memento init` then store something.
# Stash something via Python (or via Claude Code)
$ python -c "from memento import Memory; \
m = Memory(); \
m.store('I prefer dark mode in editors', 'fact', 0.8, subject_key='user.theme')"
$ memento list
01KVF2CKW772 fact imp=0.80 [user.theme] I prefer dark mode in editors
$ memento search "what theme does the user like"
1. 01KVF2CKW772 fact imp=0.80 [user.theme] I prefer dark mode in editors
$ memento show 01KVF2CKW772
Memory 01KVF2CKW772QQG4ZRPSDEH99E
kind: fact
subject_key: user.theme
importance: 0.80
source: manual
...
content:
I prefer dark mode in editors
```
If you see this — Claude Code will too. The next session, just open Claude and ask *"what theme does the user like?"* — it'll know.
---
## What's stored
Three kinds of memories:
| Kind | Use for | Example |
|------|---------|---------|
| `fact` | User preferences, project facts, conventions | "User prefers dark mode" |
| `event` | Things that happened, dated context | "Migrated from Postgres to SQLite on 2026-01-15" |
| `lesson` | Procedural rules the agent should follow | "When using sqlite-vec, always include `AND k = ?`" |
Each memory can have a `subject_key` (e.g. `user.theme`, `project.db_choice`) for deterministic lookup, plus metadata and importance (0.0–1.0).
---
## Architecture
```
┌──────────────────────────────────────────────────┐
│ Claude Code (or any MCP client) │
│ │ │
│ │ MCP protocol (JSON-RPC over stdio) │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ memento mcp_server │ │
│ │ (10 tools: memento_store, memento_recall, …) │ │
│ └──────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ memento core (Python) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ │
│ │ │ Store │ │ Recall │ │ Embedder│ │ │
│ │ │ (SQLite) │ │(vec+fts) │ │ (sbert)│ │ │
│ │ └──────────┘ └──────────┘ └─────────┘ │ │
│ └──────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ SQLite + FTS5 + vec0 (~/.local/share/…) │
└──────────────────────────────────────────────────┘
```
Everything in one SQLite file. SQLite gives ACID transactions, WAL for concurrent reads, and single-file backup. No Docker, no Postgres, no Redis.
---
## When to use `memento`
You want persistent memory that just works, runs on your laptop, doesn't phone home, and integrates with Claude Code in under a minute.
## When NOT to use it
You need multi-tenant cloud storage, embeddings for non-text modalities, or 100k+ memories per user (vector search in SQLite caps out around there).
---
## ⚠️ Auto-execute awareness
Claude Code (and other MCP clients) may auto-execute `memento_*` tools without explicit confirmation if the user enables auto-mode. Every `memento_store` call writes a row to your local SQLite file. Two practical consequences:
1. **Use `subject_key` for deterministic facts.** Free-form `memento_store` calls without a `subject_key` will dedupe via vector similarity — convenient, but you'll get a fresh row each time the wording shifts.
2. **Audit before clearing.** `memento_forget` is a soft archive (recoverable). `memento_forget --hard` and `memento_forget-prefix` are destructive — they `DELETE` rows from the on-disk SQLite file. There is no undo.
If your agent runs in a context where another process might invoke these tools, wrap your MCP server call in an explicit user prompt.
---
## Backing up and restoring
Everything is in one SQLite file. To back up:
```bash
cp ~/.local/share/memento/memory.db backup.db
# Or export to portable JSONL:
memento export ~/.local/share/memento/memory.db > backup.jsonl
```
To restore:
```bash
# From a SQLite file:
cp backup.db ~/.local/share/memento/memory.db
# From a JSONL file:
memento init ~/.local/share/memento/memory.db --force
memento import_data ~/.local/share/memento/memory.db backup.jsonl
```
## Upgrading the embedding model
If you switch `MEMENTO_EMBEDDING_MODEL` or upgrade `sentence-transformers`, old memories
have embeddings in the old dimension. Run:
```bash
memento reembed
```
This re-encodes every memory using the current model. Without it, sqlite-vec
queries on mixed-dim embeddings will crash.
---
## Usage
### CLI
```bash
memento init # create empty DB
memento verify # health check (8 checks)
memento stats # show counts, model, schema version
memento list # show recent memories (formatted)
memento show <id> # show one memory by id
memento search "query" # semantic search via CLI
memento start # run MCP server on stdio
memento export <path> > backup.jsonl # export all memories to JSONL
memento import_data <path> <file.jsonl> # import from JSONL backup
memento import <path> <pm-db-path> # import from PMB-format DB
memento reembed # re-encode stale embeddings
memento about # show user.* facts + recent events
memento forget <id> # soft-archive one memory
memento forget <id> --hard # physical delete (irreversible)
memento forget-prefix <prefix> # archive all memories by subject_key prefix
```
### Python API
```python
from memento import Memory
mem = Memory(path="~/.local/share/memento/memory.db")
# Store a fact (with subject_key for deterministic dedup)
mem.store(
content="User prefers dark mode",
kind="fact",
importance=0.8,
subject_key="user.theme",
)
# Semantic recall (results are MemoryRecord, sorted by relevance)
results = mem.recall("what theme does the user prefer?")
for r in results:
print(f"[{r.kind}] {r.content}")
# Update
mem.update(id=results[0].id, content="User prefers dark mode in editors, light in terminals")
# Forget
mem.forget(id=results[0].id)
# Browse by prefix
for item in mem.browse(subject_key_prefix="user."):
print(item.content)
```
### MCP tools
When running as an MCP server, these tools are exposed:
| Tool | Purpose |
|------|---------|
| `memento_store` | Store a fact/event/lesson |
| `memento_recall` | Semantic search across all memories |
| `memento_update` | Update content/importance/metadata |
| `memento_forget` | Soft-delete (archive); `hard=True` purges from disk |
| `memento_forget_prefix` | Soft-archive all memories by subject_key prefix |
| `memento_recent` | Browse recent memories |
| `memento_browse` | List by subject_key prefix |
| `memento_stats` | Counts, schema version, model info |
| `memento_store_many` | Atomic batch insert |
| `memento_recall_many` | Batch semantic search |
All tool names are prefixed with `memento_` to avoid collisions with other MCP servers exposing generic names like `store` or `recall`.
For migration from PMB-format DBs, use the Python API:
`from memento.importers.pmb import import_pmb`.
---
## Storage format
Single SQLite file with three tables:
- `memories` — content + metadata (subject_key, kind, importance, source, timestamps)
- `memory_fts` — FTS5 virtual table for keyword fallback
- `memory_vec` — sqlite-vec virtual table for semantic search
Schema migrations: `schema_version` table tracks applied migrations; `memento init` upgrades existing DBs in place.
---
## Testing
```bash
git clone https://github.com/UmoLab/memento
cd memento
pip install -e ".[dev]"
pytest # 179 tests, ~10 min on CPU
pytest --cov=memento # with coverage
ruff check src tests # lint
```
---
## Documentation
- [Installation guide](docs/installation.md)
- [Claude Code integration](docs/claude-code-integration.md)
- [Python & MCP API reference](docs/api.md)
- [CHANGELOG](CHANGELOG.md)
- [CONTRIBUTING](CONTRIBUTING.md)
---
## License
Apache 2.0. See [LICENSE](LICENSE).
---
## Credits
- [sqlite-vec](https://github.com/asg017/sqlite-vec) — vector search in SQLite
- [sentence-transformers](https://www.sbert.net/) — local embeddings
- [fastmcp](https://github.com/jlowin/fastmcp) — MCP server framework
- [python-ulid](https://github.com/aztechverder/python-ulid) — sortable IDs
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing