OpenSource-Hub

mempalace

CLI ツール

MemPalace/mempalace

ローカルファーストな AI メモリシステム。セマンティック検索をサポート。

概要

MemPalace は会話履歴をそのまま保存し、セマンティック検索によって取得します。プラガブルバックエンド(デフォルトは ChromaDB)を採用し、コンテンツのマイニングと検索を行うコマンドラインツールを提供します。プライバシーを保護するローカルファースト設計でありながら、オプションの外部バックエンドにも対応しています。

README プレビュー

\n\n\n\n# MemPalace\n\nLocal-first AI memory. Verbatim storage, pluggable backend, 96.6% R@5 raw on LongMemEval — zero API calls.\n\n[![][version-shield]][release-link]\n[![][python-shield]][python-link]\n[![][license-shield]][license-link]\n[![][discord-shield]][discord-link]\n\n\n\n> [!CAUTION]\n> **Beware of impostor sites.** MemPalace has no other official websites. The **only** official sources are this **[GitHub repository](https://github.com/MemPalace/mempalace)**, the **[PyPI package](https://pypi.org/project/mempalace/)**, and the docs at **[mempalaceofficial.com](https://mempalaceofficial.com)**. Any other domain (including `.tech`, `.net`, or other `.com` variants) is an impostor and may distribute malware. Details and timeline: [docs/HISTORY.md](docs/HISTORY.md).\n\n> [!IMPORTANT]\n> **Claude Code sessions expire in 30 days without auto-save hooks wired.** [Read this →](https://github.com/MemPalace/mempalace/discussions/1388)\n>\n> Need the shortest recovery/setup path? Use the [Claude Code retention setup checklist](https://mempalaceofficial.com/guide/claude-code-retention.html).\n\n---\n\n## What it is\n\nMemPalace stores your conversation history as verbatim text and retrieves\nit with semantic search. It does not summarize, extract, or paraphrase.\nThe index is structured — people and projects become *wings*, topics\nbecome *rooms*, and original content lives in *drawers* — so searches\ncan be scoped rather than run against a flat corpus.\n\nThe retrieval layer is pluggable. The current default is ChromaDB; the\ninterface is defined in [`mempalace/backends/base.py`](mempalace/backends/base.py)\nand alternative backends can be dropped in without touching the rest of\nthe system.\n\nNothing leaves your machine unless you opt in.\n\nArchitecture, concepts, and mining flows:\n[mempalaceofficial.com/concepts/the-palace](https://mempalaceofficial.com/concepts/the-palace.html).\n\n---\n\n## Install\n\nMemPalace ships a CLI, so install it in an isolated envi

FAQ (5)

トラブル対応
`--llm-rerank` で LoCoMo Avg Recall が変わらないのはなぜですか?

LoCoMo は llm_rerank_locomo() が実行される前に、融合された候補リストを top-k に切り捨てます。そのためリランカーは同じ ID セットを並べ替えるだけであり、compute_retrieval_recall はエビデンスセットへの所属を採点し、順序を無視します。これが、LLM 呼び出しが行われているにもかかわらず、--llm-rerank ありの実行となしの実行で同一のリコールが得られる理由です。

回避策: LoCoMo のリコールのみを測定する実行では --llm-rerank を省略してください。例:

python benchmarks/locomo_bench.py --granularity session --top-k 10 --mode hybrid

このフラグは LongMemEval の R@k には影響し得ます。LongMemEval ではリランキングが切り捨ての前に行われるためです。LoCoMo のリコールに影響させるには、より広い候補プールをリランクし、切り捨ての前に最終的な top-k アイテムを選択してください。素朴な「プールから k 個を選ぶ」プロンプトは複数エビデンスのリコールを低下させる可能性があるため、融合リストの先頭部分を維持し、LLM には末尾のスロットのみを埋めさせることを検討してください。CLI ヘルプと benchmarks/BENCHMARKS.md は、この制限を文書化するために更新されました。

参照 Issue #2164
トラブル対応
なぜ Mempalace mine は非常に遅く、トンネルごとに tunnels.json を書き換えるのですか?

バージョン 3.8.0–3.10.0 および develop では、mempalace/palace_graph.py の create_tunnel() がトンネルごとに tunnels.json ファイル全体を読み込み、スキャンし、書き換えています。Mine ループはこれを繰り返し呼び出すため、二次時間の計算量と過剰なディスク書き込みが発生します。

トンネル作成をバッチ化して修正してください:

1. mine ロックを取得し、tunnels.json を一度だけ読み込み、id -> tunnel のインデックスを構築する、スレッドローカルな tunnel_batch() コンテキストマネージャーを追加します。
2. create_tunnel() が同一ファイルに対するアクティブなバッチを検出し、呼び出しごとに保存せず、インデックス経由で O(1) で挿入・更新を行うようにします。
3. バッチコンテキストの終了時にトンネルリスト全体を一度だけ保存します。できれば finally 内で行います。
4. entity_tunnels_for_wing()、compute_topic_tunnels()、および topic_tunnels_for_wing() 内のループを with tunnel_batch(config): でラップします。
5. MCP ツールや明示的なユーザートンネルの動作が変わらないよう、既存の読み込み・変更・保存パスはバッチの外に残します。

参考実装:

_TUNNEL_BATCH = threading.local()

@contextmanager
def tunnel_batch(config=None):
    config = config or MempalaceConfig()
    tunnel_file = _get_tunnel_file(config)
    outer = getattr(_TUNNEL_BATCH, "state", None)
    if outer is not None and outer["file"] == tunnel_file:
        yield outer
        return
    with mine_lock(tunnel_file):
        tunnels = _load_tunnels(config)
        state = {
            "file": tunnel_file,
            "tunnels": tunnels,
            "index": {t.get("id"): t for t in tunnels if isinstance(t, dict)},
        }
        _TUNNEL_BATCH.state = state
        try:
            yield state
        finally:
            _TUNNEL_BATCH.state = outer
            _save_tunnels(state["tunnels"], config)

この変更により、以前は約 8.8k 回の完全な読み込み/保存サイクルを実行していたリフレッシュが、1 回の読み込みと 1 回の保存だけになります。報告された例では約 8 秒に短縮され、その時間の大部分は単一の JSON dump が占めています。

参照 Issue #2683
トラブル対応
FTS行が500件を超えてマッチした場合に、Mem Palaceのunion検索で最良のレキシカルマッチが欠落する問題を修正するには?

このバグは backends/chroma.py 内の ChromaCollection._lexical_search_via_sqlite にあります。フィルタなしの SQLite FTS5 クエリは ORDER BY なしで LIMIT を適用するため、SQLite は rowid/格納順でマッチを返します。その後、最初の500件のマッチが BM25 スコア化され、後に格納されたより良いマッチは一切考慮されません。

上限付きクエリを修正するには、LIMIT を適用する前に FTS 候補をランク付けします:

SELECT e.id, e.embedding_id
FROM embedding_fulltext_search
JOIN embeddings e ON e.id = embedding_fulltext_search.rowid
WHERE embedding_fulltext_search MATCH ? AND c.name = ?
ORDER BY bm25(embedding_fulltext_search)
LIMIT ?;

SQLite FTS5 では、bm25() の値は小さいほど良い結果を示します。これは他の箇所で既に使用されている FTS のランク順序と一致します。その後、返されたウィンドウにスコアを付け、上位 n_results を保持します。

v3.10.0 などの影響を受けるバージョンでの即時の回避策:

1. PR fix(search): rank the unfiltered lexical window before capping it の修正を含むリリースにアップグレードする。
2. ローカルでパッチを適用する場合は、LIMIT の前に上記の ORDER BY bm25(...) を追加する。
3. 一時的な回避策として、where フィルタを渡す。そのコードパスでは既に500行の上限が解除されている。
4. あるいは、max_candidates=500 を削除または引き上げる。ただし、これはクエリコストを増加させる可能性があり、新しい上限がすべてのマッチをカバーする場合にのみ有効。

max_distance を増やしても効果はありません。欠落しているドロワーは lexical 候補セットにも vector 候補セットにも入らないためです。

参照 Issue #2667
トラブル対応
抽出とバックアップの後に mempalace の修復が MineAlreadyRunning で失敗する問題を修正するにはどうすればよいですか?

mempalace 3.9.0/3.10.0 のレガシーな mempalace repair パスは、_extract_drawers、check_extraction_safety、および copy_palace_dir の実行中に mine_palace_lock を保持しません。フックによって起動された mempalace mine プロセスがこの時間帯にロックを取得する可能性があり、その結果、repair が後で MineAlreadyRunning で失敗し、抽出済み/バックアップ済みのデータが破棄されます。

恒久的な修正: レガシー repair の修正を含むリリースをインストールするか、cli/cmd_repair.py にパッチを適用して、backend.get_collection から _post_rebuild_cleanup までの操作全体が以下の内側で実行されるようにします:

with mine_palace_lock(palace_path):
    ...

抽出が開始される前に MineAlreadyRunning をキャッチし、ロックの保持者を示して非ゼロで終了する必要があります。Chroma バックエンドにおけるバッチ単位のロック取得は、同一スレッド上で再入可能です。

影響を受けるバージョンでの即時の回避策: マイナーを起動する Claude Code フックを無効にし、実行中のマイナーがないことを確認してから、repair を実行します:

pkill -f 'mempalace mine' || true
mempalace repair --yes

フックを無効にできない場合は、repair の全期間にわたってマイナーを阻止します:

while true; do
  pkill -f 'mempalace mine' || true
  sleep 2
done &
killer=$!

mempalace repair --yes
rc=$?

kill "$killer"
exit "$rc"

残存する locks/mine_palace_<hash>.lock ファイルは、プロセスの終了時に flock が解放されるため、通常は無害です。repair やマイナーのプロセスがまだ実行中でないこと、および新しいマイナーが引き続き拒否されることを確認した後にのみ、削除してください。

参照 Issue #2562
トラブル対応
MemPalace MCP が add_drawer や check_duplicate を呼び出すたびに HNSW インデックスを再読み込みするのを止めるにはどうすればよいですか?

PR #2593 を含むリリースへ MemPalace をアップグレードしてください。この問題は MemPalace 3.9.0 に影響します。MCP サーバーのキャッシュされた ChromaDB クライアントが、サーバー自身の書き込み後に chroma.sqlite3 の鮮度タイムスタンプを更新しなかったため、mempalace_add_drawer、mempalace_check_duplicate、mempalace_diary_write が自身の書き込みを外部からの変更として誤って扱い、HNSW インデックスを再読み込みしていました。pip install --upgrade mempalace で更新し、その後 pip show mempalace でインストールされたバージョンに #2593 が含まれていることを確認してください。修正済みのリリースがまだ利用できない場合は、PR #2593 からパッチ適用済みのビルドをインストールしてください。検索呼び出しは影響を受けません。ChromaBackend パスには #2307 で既に自身の書き込みに対する再スタンプが適用されているためです。パッチ適用後も、他のプロセスからの書き込みは次の変更時に引き続き検出されます。

参照 Issue #2535