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를 사용한 실행과 사용하지 않은 실행이 동일한 재현율(recall)을 생성하는 이유입니다.

해결 방법: LoCoMo 재현율 전용 실행에서는 --llm-rerank를 생략하세요. 예를 들면 다음과 같습니다:

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

이 플래그는 LongMemEval에서는 리랭킹이 자르기 전에 수행되므로 R@k에 영향을 줄 수 있습니다. LoCoMo 재현율에 영향을 주려면, 더 넓은 후보 풀을 리랭킹하고 절단 전에 최종 top-k 항목을 선택하세요. 단순한 "풀에서 k개 선택" 프롬프트는 다중 증거 재현율을 감소시킬 수 있으므로, 융합된 상위(head) 부분은 유지하고 LLM이 하위(tail) 슬롯만 채우도록 하는 것을 고려하세요. 이 제한 사항을 문서화하기 위해 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. 스레드 로컬 tunnel_batch() 컨텍스트 매니저를 추가합니다. 이 매니저는 mine lock을 획득하고, tunnels.json을 한 번 로드하며, id -> tunnel 인덱스를 구축합니다.
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번의 전체 로드/저장 주기를 수행하던 새로 고침이 한 번의 로드와 한 번의 저장으로 바뀌며, 보고된 예시는 단일 JSON 덤프가 대부분을 차지하는 약 8초로 감소했습니다.

원본 Issue #2683
문제 해결
500개를 초과하는 FTS 행이 일치할 때 Mem Palace union 검색에서 최적의 어휘 일치가 누락되는 문제를 해결하는 방법은?

버그는 backends/chroma.py의 ChromaCollection._lexical_search_via_sqlite에 있습니다. 필터링되지 않은 SQLite FTS5 쿼리는 ORDER BY 없이 LIMIT를 적용하므로, SQLite가 일치 항목을 rowid/파일링 순서대로 반환합니다. 그러면 처음 500개의 일치 항목만 BM25 점수가 계산되고, 나중에 파일링된 더 나은 일치 항목은 고려되지 않습니다.

제한을 적용하기 전에 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를 늘려도 도움이 되지 않습니다. 누락된 서랍이 어휘 후보 집합이나 벡터 후보 집합 어느 쪽에도 들어가지 않기 때문입니다.

원본 Issue #2667
문제 해결
추출 및 백업 후 MineAlreadyRunning 오류로 mempalace repair가 실패하는 문제를 해결하는 방법은?

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에 대한 수정이 포함된 릴리스를 설치하거나, backend.get_collection부터 _post_rebuild_cleanup까지의 전체 작업이 다음 블록 내에서 실행되도록 cli/cmd_repair.py를 패치하십시오:

with mine_palace_lock(palace_path):
    ...

추출이 시작되기 전에 MineAlreadyRunning을 포착하고 잠금 보유자와 함께 0이 아닌 값으로 종료해야 합니다. 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