Raw capture โ raw/mnemo.md
url: https://github.com/zaydmulani09/mnemo date_fetched: 2026-07-05 backfilled: true
Local-first AI memory layer for any LLM. Persistent knowledge graph, entity extraction, semantic retrieval โ no cloud required.
LLM apps built on custom pipelines have no persistent memory between sessions. mnemo is a local sidecar that extracts entities, builds a knowledge graph, and injects scored context back into your prompts โ no cloud, no Python runtime, no vendor lock-in.
mnemo is a sidecar service that watches every conversation you feed it, extracts named entities and relationships using an LLM, builds a persistent knowledge graph in SQLite, and injects relevant context back into future prompts โ automatically, in under 50ms. It works with Ollama (fully local, free), OpenAI, Anthropic, or any OpenAI-compatible API. It ships as a single static binary with zero cloud dependency.
your app
โ
โผ
POST /ingest โโโบ entity extraction (LLM) โโโบ knowledge graph (SQLite + petgraph)
โ
POST /retrieve โโโ scoring + ranking โโโ graph traversal + full-text search
โ
โผ
context_prompt โโโบ inject into your LLM prompt
/ingest(a conversation turn, a document, a note)./retrieve, mnemo runs a 6-stage pipeline: full-text chunk search โ entity name search โ graph expansion (BFS over the knowledge graph) โ relation filter โ score+rank โ assemble acontext_promptstring.context_promptinto your LLM's system prompt. Done.There are a lot of AI memory tools. Here's what makes mnemo different:
| mnemo | Most alternatives | |
|---|---|---|
| Runtime | Single Rust binary | Python daemon |
| Storage | SQLite, survives restarts | In-memory or cloud |
| Graph layer | petgraph, multi-hop traversal | None |
| Cloud dependency | Zero | Required or optional |
| LLM backend | Any OpenAI-compatible | Often locked to one |
| Retrieval | Scored + ranked, graph-expanded | Naive context dump |
mnemo is not for everyone. If you're using a managed agent harness that handles memory for you, you don't need it. mnemo is for developers building custom LLM pipelines who need persistent, structured, local memory they fully control.
The graph layer is the real differentiator โ entities are deduplicated across sessions, relationships are weighted and traversed at query time, and graph-expanded results score at 0.5x so direct matches always rank higher than inferred ones.
git clone https://github.com/zaydmulani09/mnemo
cd mnemo
docker compose up -d
# Pull the llama3 model the first time (~4 GB)
docker exec mnemo-ollama ollama pull llama3
# Verify everything is healthy
curl http://localhost:8080/health
cargo install --path crates/mnemo-api
# With Ollama
export MNEMO_LLM_BASE_URL=http://localhost:11434/v1
mnemo-api
# With OpenAI
export MNEMO_LLM_BASE_URL=https://api.openai.com/v1
export MNEMO_LLM_API_KEY=sk-...
export MNEMO_LLM_MODEL=gpt-4o-mini
export MNEMO_LLM_PROVIDER=openai
mnemo-api
install mnemo-sdk
from mnemo import MnemoClient
client = MnemoClient() # server at http://localhost:8080
client.ingest("I'm building a Rust vector database called vecdb")
print(client.get_context("what am I working on?"))
All endpoints accept and return `application/json`. Base URL: `http://localhost:8080`.
| Method | Path | Description | Request body | Response |
|---|---|---|---|---|
| `GET` | `/health` | Server + DB + LLM status | โ | `HealthResponse` |
| `POST` | `/ingest` | Store text, extract entities | `IngestRequest` | `IngestResponse` |
| `POST` | `/retrieve` | Retrieve ranked memory context | `RetrievalQuery` | `RetrievalResult` |
| `GET` | `/entities` | List entities (paginated) | `?limit&offset` | `Entity[]` |
| `GET` | `/entities/:id` | Get entity by UUID | โ | `Entity` |
| `DELETE` | `/entities/:id` | Delete entity (cascades) | โ | `{"deleted":true}` |
| `GET` | `/entities/:id/neighbors` | Knowledge graph neighbors | `?depth`(max 5) | `GraphNode[]` |
| `GET` | `/chunks` | List memory chunks (paginated) | `?limit&offset&session_id` | `MemoryChunk[]` |
| `GET` | `/chunks/:id` | Get chunk by UUID | โ | `MemoryChunk` |
| `DELETE` | `/chunks/:id` | Delete chunk | โ | `{"deleted":true}` |
| `POST` | `/search` | Full-text search entities + chunks | `{"query","limit"}` | `{"entities","chunks"}` |
| `DELETE` | `/wipe` | Delete all memory (irreversible) | header: `X-Confirm-Wipe: true` | `{"wiped":true}` |
| `GET` | `/stats` | Entity/chunk/graph counts + uptime | โ | `StatsResponse` |
**Key request/response types:**
Full endpoint documentation with curl examples: `docs/api.md`
| Variable | Default | Description |
|---|---|---|
| `MNEMO_DB_PATH` | `mnemo.db` | SQLite database file path |
| `MNEMO_PORT` | `8080` | API server port |
| `MNEMO_LLM_BASE_URL` | `http://localhost:11434/v1` | OpenAI-compatible LLM base URL |
| `MNEMO_LLM_MODEL` | `llama3` | Model name for entity extraction |
| `MNEMO_LLM_API_KEY` | `ollama` | API key (any value works for Ollama) |
| `MNEMO_LLM_PROVIDER` | `ollama` | Provider type: `ollama`,`openai`,`anthropic`,`custom` |
Pass `--config path/to/config.toml` to `mnemo-api`. See `mnemo.example.toml`:
db_path = "mnemo.db" port = 8080 [llm] provider = "ollama" base_url = "http://localhost:11434/v1" model = "llama3" api_key = "ollama" timeout_secs = 30 max_retries = 3 max_tokens = 2048 temperature = 0.1
Environment variables take precedence over TOML values. The active config source is reported in `GET /health` โ `config_source`.
Install:
`cargo install --path crates/mnemo-cli`Usage:
mnemo ingest "I use Neovim and prefer dark mode"
mnemo search "what editor do I use?"
mnemo entities
mnemo entity --neighbors
mnemo chunks
mnemo health
mnemo stats
mnemo wipe
mnemo wipe --yes
mnemo --server http://192.168.1.10:8080 stats
Install:
`pip install mnemo-sdk`See `sdk/python/README.md` for the full API reference.
**Async example:**
import asyncio from mnemo import AsyncMnemoClient async def main(): async with AsyncMnemoClient() as client: await client.ingest( "Alice is a principal engineer at Stripe working on payment infrastructure.", session_id="session-001", ) context = await client.get_context( "what does Alice work on?", session_id="session-001", ) print(context) asyncio.run(main())
A working standalone example: `examples/basic_usage.py`
Four Rust crates wired together:
| Crate | Type | Role |
|---|---|---|
| `mnemo-core` | lib | Entity extraction, graph ops, retrieval engine, DB layer |
| `mnemo-api` | bin | Axum REST API โ thin handler layer over mnemo-core |
| `mnemo-cli` | bin | CLI tool using blocking reqwest against the API |
| `mnemo-bench` | bin | Performance benchmarks (12 suites) |
Full architecture documentation: `docs/architecture.md`
Benchmarked on Apple M2, SQLite WAL mode, in-memory petgraph. Debug build numbers โ release build (`--release`) is 3โ5ร faster.
| Operation | Avg latency | Throughput |
|---|---|---|
| Entity insert (SQLite) | ~0.12 ms | ~8,300 ops/s |
| Entity lookup by ID | ~0.08 ms | ~12,500 ops/s |
| Chunk insert | ~0.14 ms | ~7,100 ops/s |
| Full-text chunk search | ~0.28 ms | ~3,500 ops/s |
| Graph neighbor (depth=1) | ~0.21 ms | ~4,700 ops/s |
| Graph neighbor (depth=2) | ~0.89 ms | ~1,100 ops/s |
| Full retrieval pipeline | ~4.2 ms | ~238 ops/s |
Run `cargo run -p mnemo-bench` to benchmark on your hardware.
cargo test --workspace # run all 122 tests make coverage # HTML coverage report (requires cargo-llvm-cov) make coverage-summary # summary to stdout
`cd sdk/python && pytest tests/ -v````
cargo run -p mnemo-bench # all 12 benchmarks
cargo run -p mnemo-bench -- --filter graph # graph benchmarks only
cargo run -p mnemo-bench -- --json out.json # save results to JSON
Current test counts: 122 Rust tests ยท 21 Python tests ยท 12 benchmarks
PRs welcome. Please run make fmt && make lint before submitting.
Open an issue first for large changes.
See CONTRIBUTING.md for full setup instructions, code style guide, and how to add a new LLM provider.
MIT โ see LICENSE