v0.7.0 Apache-2.0 Rust · Python · CLI · MCP

Encrypted memory and cache for AI agents, in one file.

MNemo gives an agent durable memory and a cache for expensive calls, inside a single encrypted .mnemo file. There's no server or vector database to run. Copy the file and the memory comes with it.

$ pip install mnemo-engine
agent.mnemo AES-256-GCM
Memoriesepisodic · semantic · procedural · working
Result cacheexact keys · similar prompts · TTL · size budgets
Search indexIVF + PQ for large files, exact scan always available
Snapshotsevery commit, restorable by id or by time
Write-ahead logone fsync per commit, recovers after a crash
one file · every page encrypted · open it anywhere

What you get

Memory and a cache, without the infrastructure

Most agent memory means running a separate vector service: another thing to deploy, and another place for secrets to leak. MNemo treats memory like SQLite treats data. It's a file.

One portable file

Memories, cache, index, write-ahead log and snapshot history all live in one .mnemo file. A plain copy is a complete, consistent backup.

Encrypted at rest

Every 8 KiB page is sealed with AES-256-GCM under a key derived with Argon2id. Changing the passphrase re-wraps one key; the data is never rewritten.

Text in, text out New

Hand MNemo plain text. It calls your embedding model, checks it's the one the file was built with, and ranks recall on meaning, recency, importance and use.

A cache for expensive calls

Cache LLM responses, tool outputs and API calls by exact key, or match near-identical prompts by meaning. Namespaces, expiry and size limits included.

MCP server built in

mnemo serve --mcp exposes memory and cache as tools to Claude Desktop, Cursor or any MCP client.

Crash-safe writes

Each commit goes through a write-ahead log with a single fsync. Kill the process mid-write and the file recovers cleanly next time it opens.

Point-in-time restore

Every commit is a snapshot. Roll back to any past transaction or moment, and roll forward again if you change your mind.

Safe to share

One writer, many readers, enforced with OS file locks. A second writer is turned away instead of corrupting the file.

For agents

Plug it into Claude, Cursor or any MCP client

Point your MCP client at a .mnemo file and the agent gets memory and caching as ordinary tools. The passphrase comes from an environment variable, never a tool argument.

aboutrememberrecallforget liststatssnapshot_list cache_putcache_getcache_stats cache_put_semanticcache_get_semantic

Add --embed-cmd and the tools accept plain text. MNemo starts your embedding program once, keeps it running, and restarts it cleanly if it misbehaves. A slow or broken embedder produces an error, never a mismatched memory.

claude_desktop_config.json
{
  "mcpServers": {
    "mnemo": {
      "command": "mnemo",
      "args": [
        "serve", "--mcp", "/absolute/path/to/agent.mnemo",
        "--embed-cmd", "python3 /absolute/path/to/embedder_server.py",
        "--embed-name", "sentence-transformers/all-MiniLM-L6-v2"
      ],
      "env": { "MNEMO_PASSPHRASE": "your-passphrase-here" }
    }
  }
}

Quick start

Memory and caching in a few lines

The same engine behind every surface. These examples use the current release, v0.7.0.

import mnemo_engine
from sentence_transformers import SentenceTransformer

MODEL = "sentence-transformers/all-MiniLM-L6-v2"
model = SentenceTransformer(MODEL)
def embed(texts):
    return model.encode(texts, normalize_embeddings=True).tolist()

with mnemo_engine.open("agent.mnemo", "a long passphrase", dimensions=384) as db:
    db.set_embedder(embed, name=MODEL, dimensions=384)   # checked against the file

    # Durable memory, plain text in and out
    db.remember_text("the user prefers dark mode", "semantic", importance=0.8)
    for hit in db.recall_text("which theme does the user like?", top_k=5):
        print(round(hit["score"], 3), hit["content"])

    # Cache an expensive call
    prompt = "Summarize the release notes"
    hit = db.cache_get("llm", prompt)
    if hit is None:
        answer = call_llm(prompt)                # your LLM call
        db.cache_put("llm", prompt, answer, ttl_secs=3600)
    else:
        answer = hit["value"].decode()

Multi-signal recall

Ranked on more than similarity

An agent needs the right memory, not just the closest vector. Every candidate is scored on four signals, with weights you can set per query. The three bonuses are scaled by similarity, so an unrelated memory can't win by being new, important or popular.

score =
α · similarity

How close the meaning is: cosine, dot product or L2.

+ similarity
× (
β · recency

Counted from when the memory was stored. Fades with a 7-day half-life by default.

γ · importance

A 0–1 weight set when the memory is stored, centred on 0.5.

δ · uses

A capped boost for memories the agent keeps coming back to, so popular memories can't snowball.

)

Episodic

What happened: conversation turns and events. Sessions promote their turns here when they close.

Semantic

What's known: facts about the user, the project and the world.

Procedural

How to behave: preferences, rules and working conventions.

Working

Right now: the current session's scratchpad, kept or discarded when it ends.

Agent-first

Every file introduces itself

Hand an agent a .mnemo file and its passphrase, and one command tells it what the file is: which embedding model it expects, the conventions used, and any notes the author left. No separate README required.

  • Self-describing. A manifest stored inside the file, printed by mnemo about or db.about().
  • Ready from creation. mnemo init adds a starter manifest so new files are never blank.
  • Same everywhere. The Rust library, Python package, CLI and MCP server share one engine and one behaviour.
$ mnemo about agent.mnemo
# agent.mnemo  (66 memories · 384-dim · encrypted · 33 snapshots)

### MANIFEST
This .mnemo file is the project memory for MNemo.
Embedder: sentence-transformers/all-MiniLM-L6-v2
(384-dim, normalized). Default agent_id: cursor-agent.

### onboarding / mission
Ongoing project context lives in this file, so new
AI sessions stay aligned without relying on chat history.

## Quick start
  mnemo list   agent.mnemo
  mnemo recall agent.mnemo --query VEC
  mnemo get    agent.mnemo <id> --verbose

Security & reliability

Private by default, tamper-evident on disk

Without the passphrase the file is opaque, and changed bytes are detected rather than silently trusted.

  • Pages are pinned to their position. A valid encrypted page moved to another slot fails authentication.
  • The header is sealed. Pointing it at an older catalog is caught on open as tampering.
  • No password oracle. A wrong passphrase and a damaged key look identical.
  • Safe to copy and keep writing. Every writing session uses a fresh random nonce prefix, so two diverged copies of a file never reuse encryption nonces (fixed in v0.5.2; see the advisory).
  • Tested hard. Fuzzed parsers, property tests with simulated crashes, and a dependency audit on every change.
  • No unsafe code. The core crate forbids it outright.
  • Verifiable releases. PyPI packages are published from CI with signed provenance (Trusted Publishing).

Out of scope, stated plainly: anyone with write access can still delete or truncate the file, swapping in an older valid copy of the whole file can't be detected from inside it, and anyone who has the passphrase is the owner. Read the full security model.

How the keys fit together

passphraseArgon2idkey-encryption key
key-encryption keywrapsrandom 256-bit data key
data keyAES-256-GCMevery 8 KiB page
Page 0 · header
format version, key-derivation settings, wrapped data key
plaintext + sealed
Write-ahead log
pending commits, replayed after a crash
encrypted
Records
memories and cache entries
encrypted
Catalog · index · cache directory
what's where, plus the IVF+PQ search index
encrypted
Snapshot manifest
one entry per commit, for restore
encrypted

Performance

Measured, not promised

We only publish numbers we've measured. These are from an Apple M1 Pro (release build, 384-dimension vectors). See the full results.

~1 µs
Exact-key cache hit
Looking up a cached LLM or tool result in an open file.
~0.4 ms
Similar-prompt cache hit
Matching by meaning across a 500-entry cache.
~15 ms
Open an encrypted file
Almost all of it is Argon2id, on purpose: it makes guessing the passphrase expensive. Long-running apps pay it once.
~19 ms
Store a memory durably
Bound by full disk syncs. Commit 100 memories at once and each costs about 0.25 ms.
~105 ms
Check every memory, 10K-memory file
Exact search with no index, every candidate decrypted. 1.05 s at 100K.
~9.4 ms
Indexed search, 100K memories
Finds 98% of the true top-10 at the default settings (v0.6.0). ~1.4 ms at 10K, ~134 ms at 1M.

From v0.5.1, Apple Silicon and ARM Linux builds use the CPU's hardware AES, which makes scans 3–6× faster than v0.5.0, depending on the chip.

Roadmap

Where MNemo is headed

Built in the open, one reviewed release at a time. Full history in the changelog.

Shipped v0.4 – v0.7

  • Better ranking: the right memory comes first more often, and frequently shown memories no longer crowd out the relevant one
  • Accurate index search: the default finds 96–98% of the true best matches, up from 40%
  • Stronger crash recovery: a damaged file header is rebuilt from the write-ahead log, and tampering is always reported
  • Plain text in and out from Python, the CLI and MCP; MNemo calls your embedding model
  • A check that each file is used with the embedding model it was built with
  • Result cache: exact keys and similar prompts
  • MCP server for Claude, Cursor and other clients
  • File locking and read-only opens
  • Fuzzing, property tests and dependency audits in CI
  • Benchmarks at 100K–1M memories, plus a ranking-quality test
  • Hardware AES on ARM: 3–6× faster scans
  • Automated releases, with signed provenance on PyPI

Next in progress

  • Seamless agent memory: edit memories in place, filter recall by session or tag, and a Claude Code plugin that loads and saves memories automatically
  • Keyword search combined with meaning-based search, so exact names, versions and ids are found reliably

After that planned

  • Speedups and smaller files, wherever the benchmarks point
  • An optional built-in local embedding model, no separate program needed
  • Smarter memory: merge duplicates, summarise sessions, link related memories, forget stale ones
  • A Node.js package and framework integrations

Give your agent a memory it can carry

Open source under Apache-2.0. Written in Rust, with Python, CLI and MCP on top.