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 整合