lean-memory is an embedded, local-first agent memory system that requires no server, daemon, or mandatory cloud keys. It extracts facts from natural language, stores them in a SQLite file per namespace, and recalls them through hybrid dense and sparse retrieval. Old facts are never deleted, but superseded, and can be queried at any past point in time. It works fully offline out of the box, and optional components unlock real model quality.
Main capabilities:
- Memory extraction: each mem.add() runs a four-pass hybrid extraction pipeline: rules (regex and dateparser for common predicates), GLiNER2 open-vocabulary NER candidate generation, router (recall-biased escalation, with low-confidence, coreference, and inferential facts escalated to the LLM channel), LLM typing (constrained relation typing via a local Ollama model).
- Contradiction detection: runs from lowest to highest cost (slot matching → cosine → token containment → LLM). Conflicting facts are superseded rather than deleted, and old facts retain is_latest=False and a superseded_by pointer.
- Entity identity resolution: based on normalized name keys (NFC + Unicode case folding + whitespace folding), so that Acme, ACME, and acme are treated as the same subject, with full Unicode folding supported, and punctuation and diacritics deliberately not folded.
- Retrieval: fuses two-stage Matryoshka dense search (256-dimensional coarse KNN → full-dimensional rescoring) with BM25 sparse search, applies RRF fusion, reranks with a cross-encoder, and scores with salience decay (0.6·relevance + 0.2·recency + 0.2·importance).
Usage:
- MCP server: gives any MCP agent persistent local memory, with three tools (memory_add, memory_search, memory_clear), one SQLite file per namespace, and data never leaving the local machine. The first run downloads three open models (about 2.0 GB total: Qwen3-Embedding-0.6B, Ettin-32M reranker for retrieval, plus GLiNER2-base at about 0.8 GB for real extraction, all ungated). You can warm it up once first to avoid the MCP client waiting for downloads.
- Data root directory: LM_DATA_ROOT (defaults to ~/.lean_memory). It also supports offline-only mode; the server will opportunistically upgrade the backends corresponding to additionally installed components ([models] → real embedder + reranker, [extract] → GLiNER2 extraction), otherwise falling back to deterministic stub backends (suitable for CI, but semantically meaningless in real use — it is recommended to install [mcp,models,extract]).
- Optional [llm] extra component: the standard [mcp,models,extract] installation has no LLM-typed channel, and about 15% of upgraded candidates (almost all inferential facts) are typed by a deterministic stub rather than a model. Assertional facts are unaffected; inferential-type facts are effectively second-class citizens on the default path. Adding [llm] (a local Ollama model) upgrades this upgrade layer to real constrained typing.
- Sleep-time maintenance and review: an offline task that runs during off-peak hours, deduplicates, summarizes, and demotes low-value records, then hands judgment-based operations to the user for confirmation the next morning by clicking in the Web console or Claude Code. The CLI (lean-memory-maintain) is the primary trigger, defaults to dry-run, and reports the operations that would be performed without writing anything. --root defaults to $LM_DATA_ROOT; adding --namespace NS runs only a single namespace. A safe window for nightly 3 a.m. runs can be scheduled via crontab.
- Next-day review: judgment-based operations (near-duplicate merges, summaries, evictions) are staged as proposals, and stored memories do not change until approval. Run the /review-memory plugin command (or invoke the review-memory-maintenance MCP prompt on the console server), and Claude will guide the user through the queue grouped by entity, provide before-and-after evidence, and record only the rulings the user gives. Four MCP tools support this: memory_maintenance_run (dry-run by default), memory_maintenance_status, memory_review_queue, and memory_review_decide, available on the core lean-memory-mcp server and both console MCP interfaces. Setting LM_MAINT_AUTO=1 opts in to background automatic runs (safe window only), off by default.
- Console review page: the same queueColumns are grouped by entity, and each proposal has before-and-after evidence (near-duplicates are two texts + cosine, summaries are source + suggested text, eviction is scoring evidence), action verbs include Approve / Keep / Edit-then-approve / Promote, batch approval by entity is supported, as well as a maintenance run button (dry-run by default; applying requires confirmation). The two frontends drive the same proposal store and use compare-and-swap decisions to avoid duplicate application.
Safety: nothing is ever deleted—maintenance only appends, retires (using the same superseded_by flip as ordinary supersession), or demotes to a cold tier, so the full history remains queryable as of any past point in time, and storage predicates are bit-for-bit identical and pinned by executable tests. Only two transitions apply automatically: exact-duplicate retirement and strict eviction bands; all judgmental operations are staged for human handling, and unreviewed proposals expire after 30 days rather than being applied automatically—silence never means consent. Cold-demoted facts remain accessible via as_of queries and search(..., include_cold=True), and promotion back to the hot tier is limited to explicit operations, so reads never persistently change what the agent sees.
Use cases: individuals or teams that need persistent memory for local or MCP agents and value data not leaving the local machine and full traceability of history; suitable for offline environments, CI testing, and scenarios that require human review of memory maintenance.
Limitations: the default backend is an offline stub, and semantics are meaningless; production-grade retrieval requires installing real models. The standard installation lacks an LLM typing channel, and inferential facts are handled by the stub. Entity name normalization does not fold punctuation or diacritics, and two genuinely different subjects that differ only by case (such as the planet Mercury and the element mercury) are merged into one. Public benchmark runs (LongMemEval/LoCoMo) are intentionally deferred until after release.