lean-memory

io.github.Wuesteon由 GitHub 账号 Wuesteon 发布v0.3.0更新于 Oct 24, 2026

Embedded, local-first agent memory: one SQLite file per namespace, no server, no cloud.

发布方自己的服务:Memory.fit

已验证STDIO仅桌面数据库知识与记忆

概览

AI 生成的概览

本地优先的智能体记忆服务器,按命名空间将事实存入 SQLite 文件,让助手离线添加、检索和清除记忆。

可以做什么
  • 以自然语言向命名空间添加事实,并自动取代过时事实
  • 用稠密加稀疏的混合检索与重排序搜索记忆,支持按时间点查询
  • 清除某个命名空间的记忆
  • 运行维护试运行、查看状态、列出待审队列并记录审核决定
  • 保留完整历史:事实只被退役或降级,不会被删除
适用场景
适合希望 Claude Code、Claude Desktop 等助手跨会话记住用户或项目事实、又不愿把数据发往云端的场景。适用于本地、离线优先且需要按租户隔离持久记忆的配置。
运行要求
作为本地 stdio 进程运行,从 PyPI 安装(uvx 或 pip),服务器桥接需 mcp 附加包。可选的 models 与 extract 附加包首次运行会下载约 2 GB 开源模型;llm 附加包需要本地 Ollama 模型。LM_DATA_ROOT 指定数据目录,默认 ~/.lean_memory。无需 API 密钥。
安装前请注意
未安装 models 与 extract 附加包时会退回确定性的桩后端,对真实使用没有语义意义。memory_clear 工具与维护的 apply 模式会改动已存记忆,不过维护默认仅试运行,需人工判断的变更会先暂存待审。记忆文件保存在 LM_DATA_ROOT 下的本地磁盘。

安装

在 SourceWeft 中

  1. 打开 控制台中的 lean-memory,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

lean-memory

[test] [PyPI] [Wuesteon/lean-memory MCP server]

Embedded, local-first agent memory. No server, no daemon, no mandatory cloud key.

Status (2026-07): first public release line (0.2.1) is live on PyPI and the MCP Registry (MCP-first launch); the Claude Code plugin ships in this repo (marketplace listing pending). Roadmap and rationale: docs/superpowers/specs/2026-07-08-strategic-direction-design.md. Public benchmark runs (LongMemEval/LoCoMo) are deliberately deferred until after launch; the harness is complete (bench/phase2_*.py) and the engine flaws it exposed are fixed — see docs/phase2-learnings.md.

python
from lean_memory import Memory
mem = Memory(root="./data")
mem.add("user-42", "I work at Acme Corp.")mem.add("user-42", "I now work at Globex.")          # supersedes Acme automatically
mem.search("user-42", "where does the user work?")   # → "I now work at Globex."

[lean-memory quickstart]

Facts are extracted from natural language, stored in a per-namespace SQLite file, and retrieved with hybrid dense+sparse search. Old facts are never deleted — they're superseded and queryable at any past point in time.

Install

bash
pip install lean-memory

Runs fully offline out of the box. Optional extras unlock real model quality:

ExtraWhat it adds
lean-memory[models]Real embedder + reranker (Qwen3-0.6B + Ettin-32M)
lean-memory[extract]GLiNER2 candidate generation for richer extraction
lean-memory[llm]Ollama-backed LLM typing pass
lean-memory[mcp]MCP server bridge for Claude Desktop / Claude Code
lean-memory[examples]Terminal demo agent (requires anthropic SDK)

Quickstart

python
from lean_memory import Memory
mem = Memory(root="./data")   # one SQLite file per namespace, stored under ./data/
# Store facts in natural languagemem.add("alice", "I work at Stripe.")mem.add("alice", "I now work at Vercel.")   # supersedes Stripe automatically
# Retrieve — the superseded Stripe fact drops out; only the current one is returnedresults = mem.search("alice", "what does Alice do for work?", k=3)for hit in results:    print(hit.fact.fact_text, hit.final_score)# → I now work at Vercel. 0.89
# Point-in-time query — what was true at a specific moment?mem.search("alice", "employer", as_of=1_700_000_000_000, is_latest_only=False)  # epoch ms
# Always close when done (flushes WAL)mem.close()

Demo Agent

A terminal chatbot showing the full memory loop — add, retrieve, supersede, restart. The demo script lives in the repo (it is not installed with the package):

bash
git clone https://github.com/Wuesteon/lean-memory && cd lean-memorypip install -e '.[examples]'export ANTHROPIC_API_KEY=sk-ant-...python examples/chat.py                  # uses offline stubs by defaultpython examples/chat.py --namespace bob  # separate memory tenant, persists across restarts

No API key? The demo still runs — it echoes the retrieved memory context instead of calling Claude, so you can watch the engine work offline.

MCP Server — memory for Claude Code / Claude Desktop

Give any MCP agent persistent local memory: three tools (memory_add, memory_search, memory_clear), one SQLite file per namespace, nothing leaves your machine.

bash
pip install 'lean-memory[mcp,models,extract]'

First run downloads three open models (~2.0 GB total: Qwen3-Embedding-0.6B

  • Ettin-32M reranker for retrieval, plus GLiNER2-base (~0.8 GB) for real extraction — all ungated). Pre-warm once so your MCP client never waits on a download:
bash
python -c "from lean_memory.embed.sentence_transformer import SentenceTransformerEmbedder; \from lean_memory.retrieve.rerank import CrossEncoderReranker; \SentenceTransformerEmbedder().embed_one('warm'); CrossEncoderReranker().score('warm', ['up']); \from lean_memory.extract.gliner_extractor import Gliner2Generator; from lean_memory.types import Episode; \Gliner2Generator().generate(Episode(namespace='w', raw='I work at Acme.', t_ref=0, source='user'))"

Claude Code:

bash
claude mcp add lean-memory -- lean-memory-mcp

Claude Desktop — add to mcpServers (or copy examples/mcp_config.json):

json
{ "lean-memory": { "command": "lean-memory-mcp", "env": { "LM_DATA_ROOT": "~/.lean_memory" } } }

Data root: LM_DATA_ROOT (default ~/.lean_memory). Works offline-only too — the server opportunistically upgrades each backend that its extra is installed for ([models] → real embedder + reranker, [extract] → GLiNER2 extraction) and otherwise falls back to deterministic stub backends (fine for CI, semantically meaningless for real use — install [mcp,models,extract]).

What the optional [llm] extra buys. The canonical [mcp,models,extract] install has no LLM typing pass, so the ~15% of candidates that escalate — almost all of them inferential (derives) facts — are typed by a deterministic stub instead of a model. Assertional facts are unaffected; inference-type facts are effectively second-class on the default path. Adding [llm] (a local Ollama model) upgrades that escalated tier to real constrained typing. See ARCHITECTURE.md → Known Limitations.

Sleep-time maintenance & review

Memory accumulates cruft: the same fact restated a dozen ways, old records that never come up, clusters begging to be summarized. lean-memory cleans it up the way sleep consolidates memory — an offline job you run off-hours that dedupes, summarizes, and demotes low-value records, then hands you the judgment calls to click through the next morning, in the web console or conversationally in Claude Code.

The CLI (lean-memory-maintain) is the primary trigger. It is dry-run by default — it reports what it would do and writes nothing:

bash
lean-memory-maintain --root ~/.lean_memory              # dry-run: report only, zero writeslean-memory-maintain --root ~/.lean_memory --apply      # auto-apply safe transforms + stage the restlean-memory-maintain --root ~/.lean_memory --auto-only   # with --apply: ONLY the provably-safe band, stage nothinglean-memory-maintain --root ~/.lean_memory --json        # one machine-readable object, stable keys

--root defaults to $LM_DATA_ROOT; add --namespace NS to run a single namespace instead of every *.db under the root. Overnight, on a schedule — one crontab line runs the safe band nightly at 3am and stages everything else for you:

cron
0 3 * * *  lean-memory-maintain --root ~/.lean_memory --apply >> ~/.lean_memory/maintain.log 2>&1

Next-morning review in Claude Code. Judgment calls (near-duplicate merges, summaries, evictions) are staged as proposals — nothing changes in stored memory until you approve. Run the /review-memory plugin command (or invoke the review-memory-maintenance MCP prompt on the console server) and Claude walks you through the queue, grouped by entity with before/after evidence, recording only the verdicts you give. Four MCP tools back it — memory_maintenance_run (dry-run by default, like the CLI), memory_maintenance_status, memory_review_queue, and memory_review_decide — available on the core lean-memory-mcp server and both console MCP surfaces. Set LM_MAINT_AUTO=1 to opt into a background auto-run (safe band only) on the first tool call of a stale namespace; it is off by default.

Or click through it in the console. The memory console ships a Review page: the same queue grouped by entity, before/after evidence per proposal (both texts + cosine for near-duplicates, sources + proposed text for summaries, score evidence for evictions), with Approve / Keep / Edit-then-approve / Promote verbs, batch-approve per entity, and a run-maintenance button (dry-run by default; apply sits behind a confirm). Both frontends drive the same proposal store with compare-and-set decisions, so deciding in one place shows up as "already decided" in the other instead of double-applying.

The safety story in one paragraph. Nothing is ever deleted — maintenance only appends, retires (the same superseded_by flip ordinary supersession uses), or demotes to a cold tier, so your full history stays queryable as-of any past point in time, bit-for-bit identical at the store predicate and pinned by executable tests. Only two transforms auto-apply: exact-duplicate retirement and a strict eviction band; everything judgmental is staged for a human, and an unreviewed proposal expires after 30 days rather than auto-applying — silence is never consent. Cold-demoted facts stay reachable via as_of queries and search(..., include_cold=True), and promotion back to the hot tier is explicit-only, so a read never durably changes what your agent sees.

Real Model Quality

The default backends are offline stubs — deterministic and dependency-free, but semantically meaningless. Swap in real models for production-quality retrieval:

bash
pip install 'lean-memory[models]'

With Qwen3-Embedding-0.6B + Ettin-32M reranker, retrieval jumps from 1/5 to 4/5 on the internal benchmark with zero code changes.

For benchmark results, architecture decisions, and implementation status see ARCHITECTURE.md.

How It Works

Each mem.add() call runs a 4-pass hybrid extraction pipeline:

  1. Rules — regex + dateparser for common predicates (works_at, lives_in, …)
  2. GLiNER2 — open-vocabulary NER candidate generation (offline stub by default)
  3. Router — recall-biased escalation: low-confidence, coreference, and inferential (derives) facts escalate to the LLM pass
  4. LLM typing — constrained relation typing via a local Ollama model (stub by default)

Contradiction detection runs cheap-first (slot match → cosine → token subsumption → LLM). Conflicting facts are superseded, not deleted — the old fact stays with is_latest=False and a superseded_by pointer.

Entity identity resolves on a normalized name key — NFC + Unicode case-fold + whitespace collapse — so Acme, ACME and acme are one subject and dedupe/supersession actually apply to them. It is a full Unicode fold, not SQLite's ASCII-only NOCASE: Café/CAFÉ and ЖУК/жук collate too. Punctuation and diacritics are deliberately not folded (Yahoo! ≠ Yahoo, Café ≠ Cafe), and the display name keeps the first spelling you used. The trade-off: two genuinely distinct subjects differing only by case (Mercury the planet vs mercury the metal) collate into one — nothing is deleted, and the retired fact stays readable via search(as_of=…, is_latest_only=False).

Retrieval fuses two-stage Matryoshka dense search (256-dim coarse KNN → full-dim (1024 for the default embedder) re-score) with BM25 sparse, applies RRF fusion, reranks with a cross-encoder, and scores with salience-decay (0.6·relevance + 0.2·recency + 0.2·importance).

Develop

bash
git clone https://github.com/Wuesteon/lean-memorycd lean-memorypython -m venv .venv && source .venv/bin/activatepip install -e '.[dev]'pytest -q    # full offline suite, no downloads

Project Layout

src/lean_memory/  memory.py                   Memory facade — the public API  types.py                    Episode / Fact / RetrievedFact types  store/                      Store interface + SqliteStore (vec0 + FTS5)  embed/                      Embedder interface, FakeEmbedder, SentenceTransformer  extract/                    4-pass extraction pipeline  retrieve/                   Reranker interface, retrieval pipelineexamples/  chat.py                     Terminal demo agent  mcp_config.json             Drop-in MCP client configtests/                        offline test suitebench/                        Retrieval quality + BET-2 ablation harnesses

License

Apache-2.0

来源:README.md,提交 64fcbca

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.3.0最新Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

其他 Memory 集成