Releases: MemPalace/mempalace
Release list
v3.9.0 — one hub for every agent
v3.9.0 — one hub for every agent
One hub now serves every agent. CLI search reuses the live palace index instead of loading another multi-gigabyte HNSW copy, concurrent searches stop blocking each other, and skill-first coordination plus opt-in release awareness make shared-brain fleets easier to operate safely.
Shared hub and search
mempalace searchreuses a healthy live Hub. On the reported 4.99-million-vector palace, two direct CLI searches held about 18.6 GB of private RSS. Forwardable searches now reuse the Hub collection while preserving filters, ranking, output, authentication, configuration negotiation, and safe fallback behavior. (#2379)- Hub reads run concurrently. Searches no longer serialize behind one exclusive HTTP dispatch lock; reads share a writer-preferring lock while mutations remain exclusive. (#2398)
- Search results are clearer and faster to enrich. Public similarity is the raw vector score, closet boost remains in effective ranking, source lookups are indexed, and duplicate enriched passages are removed. (#2399, #2143)
- A private-palace benchmark is included for product search evaluation without exposing private queries or corpus text. (#2400)
Agent coordination and operations
- Skill-first setup and task handoff. The guided setup skill can bootstrap private or shared-brain installations, render canonical rules, assign stable fleet identities, and validate logstream readiness. Task creation now records an immutable base commit and complete definition of done before controlled launch. (#2374, #2361)
- Release awareness is explicit and opt-in. Agents can surface cached update state and prepare an exact upgrade plan without blocking, auto-installing, or silently enabling network checks. (#2376)
- Logstream gains topic routing and reverse pagination, making focused coordination and newest-first inspection practical without weakening append-only cursor guarantees. (#2397)
Correctness and resource safety
- Unreadable configuration is never overwritten. Invalid files are preserved, writes are atomic where possible, symlinks remain intact, and UTF-8 project configuration is handled consistently. (#2357, #2353, #2369)
- Drawer mutations purge stale closet entries, single conversation files mine correctly through a running Hub, and absent SQLite databases no longer report a false clean integrity verdict. (#2355, #2282, #2291)
- Qdrant bounded reads stop scanning whole collections, and EmbeddingGemma internal batches can be reduced for long drawers on memory-constrained hardware. (#2384, #2383)
A big thank-you to everyone who contributed. This release includes 29 merged PRs and seven first-time contributors.
Install: pip install -U mempalace==3.9.0
What's Changed
- docs: refresh the release entry-point check and plugin tool counts by @igorls in #2348
- docs(shared-brain): teach the from-zero guide about logstream watch by @igorls in #2349
- docs(coordination): wake for replies, and keep announcements silent by @igorls in #2352
- fix(mcp): report an absent integrity verdict instead of a clean one (#2290) by @mvalentsev in #2291
- docs: add branching model to CONTRIBUTING.md by @jjcav84 in #2246
- fix(sqlite_exact): cross-handle cache invalidation and filtered id lookups by @igorls in #2362
- fix(search): return distinct passages after closet enrichment by @fatkobra in #2143
- fix(graph): report complete palace graph stats by @MichaelWave369 in #2288
- feat(cli):
mempalace rules— render the canonical shared-brain rules block by @igorls in #2361 - fix(mcp): purge stale closets on drawer update and delete by @AmirF194 in #2355
- fix(search): expose MCP candidate union by @iroiro147 in #1964
- fix(config): read and write project YAML as UTF-8 by @masalu0105-gif in #2353
- feat: add skill-first task coordination by @igorls in #2374
- fix(config): init() persists the resolved palace_path, not the hardcoded default by @AmirF194 in #2369
- fix(qdrant): send versioned User-Agent header by @MichaelWave369 in #2365
- fix(miner): include C and C++ source files by @MichaelWave369 in #2364
- fix(config): stop writing over a config.json that was never read (#2356) by @mvalentsev in #2357
- fix(mcp): accept a single conversation file as a convos mine source by @rubicon in #2282
- feat: add opt-in update awareness by @igorls in #2376
- chore: sync main release history into develop by @igorls in #2396
- feat: add logstream topic routing and reverse pagination by @igorls in #2397
- fix: align pre-commit ruff pin with pyproject and CI by @SomSamantray in #2342
- chore(deps): bump docker/login-action from 4.5.2 to 4.6.0 by @dependabot[bot] in #2318
- fix(qdrant): bound get()'s scroll to offset+limit instead of the full collection by @AmirF194 in #2384
- fix: let shared hub reads run concurrently by @igorls in #2398
- fix: speed up closet search enrichment by @igorls in #2399
- feat: add private Palace search benchmark by @igorls in #2400
- fix(embedding): make EmbeddingGemma sub-batch size overridable by @AmirF194 in #2383
- fix(cli): forward search to live palace hub by @RoshanDev in #2379
- chore(release): 3.9.0 by @igorls in #2401
- release: promote v3.9.0 to main by @igorls in #2402
New Contributors
- @jjcav84 made their first contribution in #2246
- @MichaelWave369 made their first contribution in #2288
- @AmirF194 made their first contribution in #2355
- @iroiro147 made their first contribution in #1964
- @masalu0105-gif made their first contribution in #2353
- @SomSamantray made their first contribution in #2342
- @RoshanDev made their first contribution in #2379
Full Changelog: v3.8.0...v3.9.0
v3.8.0 — fast large palaces, lean MCP proxies, wakeable agents
v3.8.0 — fast large palaces, lean MCP proxies, wakeable agents
Large palaces get fast and stay small in 3.8.0. Chroma metadata tools no longer cold-load HNSW, sqlite_exact stops scanning and hydrating the whole palace for common reads, long-running Chroma servers stop rebuilding their client on their own writes, and proxied MCP sessions no longer import a storage stack they never use. Agents also gain a persistent logstream watch primitive so coordination can wake a harness instead of relying on repeated five-minute waits.
Performance
- Chroma metadata reads skip the vector index. On a 1.7 GB / 165k-drawer palace, wing-scoped
list_drawers(limit=20)fell from 2.31 s and 1148 MB peak RSS to 0.01 s and 86 MB.list_drawersand tunnel reads now query Chroma's SQLite metadata directly, push filters into SQL, and hydrate only the requested previews. (#2314) sqlite_exactcommon reads no longer walk the whole palace. On a live 167k-drawer / 166k-closet palace,mempalace_statusfell from 6997 ms to 1045 ms and warmmempalace_searchfrom 6364 ms to 210–1600 ms. Vector ranking is batched and cached, top-k documents are hydrated afterward, equality filters paginate in SQL, taxonomy results are cached, andwing/room/hallgain indexed generated columns without rewriting the 1.6 GB embedding table. (#2308, #2311, #2313)- Long-running Chroma servers stay flat instead of reloading HNSW on their own writes. Across eight searches, measured RSS changed from 951 MB → 3522 MB before to 940 MB → 965 MB after. Replaced clients are closed, while genuine external database changes still trigger a rebuild. (#2307)
- Hub-proxied MCP sessions are thin. A plain stdio proxy now imports only the forwarding path and lazily loads the full server only if local fallback is needed. A proxied session runs at roughly 17 MB, with import weight falling from about 80 MB to 24 MB—avoiding roughly 3.9 GB across a 50-agent fleet. (#2312)
Agent coordination
mempalace logstream watchprovides a durable wake-up loop. It owns cursor advancement, supports repeated type filters, agent self-exclusion, persistent state files, idle exit, and NDJSON follow mode. Cursorless first runs start at the live tip; restarts may replay an event but do not silently miss one. (#2315)- The monitoring protocol now documents the safe resume cursor. Cross-replica events are appended in arrival order, so
since_event_id—not a wall-clock timestamp—is the resumable high-water mark. Tool descriptions and the shared coordination protocol now put that rule where agents use it. (#2315)
Integrity and operations
sync --applyno longer deletes drawers whose source file it could not reach. OnePath.exists()separated keep from remove, so an unreadable directory, a path component that is a regular file, and a volume that is not mounted all answered the same as a deletion — a project mined from a mounted volume could lose every drawer to onesync --applywhile the volume was away, and come back empty. Removal now asks for corroboration rather than a probe: a file that is not at its path is removable only while the palace can still see a source of its own, a regular file, in that same directory. Everything uncorroborated lands in a newunresolvedbucket, never pruned and reported the way removals are. (#2320)- EmbeddingGemma cannot silently store NaN or zero vectors through CoreML auto-selection on Apple Silicon. Auto mode avoids the affected provider/model pair, and every vector is checked for a finite, non-zero norm before use. CUDA, DirectML, and other models are unchanged. (#2283)
- FTS5 auto-heal verifies and repairs the content table before rebuilding the index. It uses Chroma's metadata copy as authority where possible and declines to guess when integrity cannot be established. (#2279)
- Mesh status is consistent across transports. The hub publishes a token-free, last-known-good estate snapshot so
mempalace_mesh_peerscan report reachability and profiles from stdio as well as HTTP. (#2309) - Filesystem edge cases fail safely.
sweepreports failed stats,inithandles unreadable manifest paths, andsplitrefuses FIFO or symlink output targets instead of blocking or writing through them. (#2244) - Published containers gain provenance and SBOM attestations. Release documentation also adds Termux PRoot installation guidance, KG supersede examples, and clarified hook write-routing scope. (#2097, #2139, #2059, #2123)
A big thank-you to everyone who contributed to this release. Contributors and first-time contributors are credited below.
What's Changed
- docs: align website contributing guide with root (#1980) by @mvalentsev in #1996
- fix(ingest): finish the non-regular-file guards left out of 3.7.1 (#2221) by @mvalentsev in #2244
- fix(ci): replace inactive owner in CODEOWNERS by @igorls in #2285
- chore(deps): bump docker/login-action from 4 to 4.5.2 by @dependabot[bot] in #2117
- chore(deps): bump actions/setup-python from 6 to 7 by @dependabot[bot] in #2073
- ci: attach provenance and SBOM attestations to the published image by @kobihikri in #2097
- docs: clarify hook write routing release scope by @Taylor-yuhb in #2123
- docs: document KG supersede usage by @ggettert in #2059
- docs: add Termux PRoot installation guide by @seoseo-ai in #2139
- test: add knowledge_graph metadata coverage by @fatkobra in #913
- test: add palace_graph ranking and limits coverage by @fatkobra in #916
- test(benchmarks): enforce the 100ms startup injection budget by @arnoldwender in #1140
- fix(benchmarks): UTF-8 encoding + ASCII print chrome on Windows for the 3 sibling runners by @jphein in #1382
- fix: remove hardcoded fallback names from split_mega_files by @adv3nt3 in #166
- revert: palace_graph ranking tests written against the pre-f68cb8d API (#916) by @igorls in #2301
- fix(chroma): stop the client cache invalidating on its own writes by @igorls in #2307
- fix(sqlite_exact): speed up query and status on large palaces by @igorls in #2308
- fix(mesh): publish the estate so every transport can report it by @igorls in #2309
- fix(sqlite_exact): cut remaining palace-wide read paths by @igorls in #2311
- perf(mcp): make a proxied stdio session stop loading the storage stack by @igorls in #2312
- fix(sqlite_exact): index wing/room/hall for structured access by @igorls in #2313
- fix(chroma): read list_drawers and tunnels from sqlite, skip HNSW by @igorls in #2314
- feat(logstream): background watcher agents can be woken by, plus the monitoring protocol by @igorls in #2315
- fix(embedding): never let CoreML return NaN vectors for embeddinggemma by @marcoaperez in #2283
- fix(repair): check the FTS5 content table before rebuilding from it (#2278) by @mvalentsev in #2279
- chore(release): 3.8.0 by @igorls in #2316
- fix(sync): require an established absence before removing a drawer (#2320) by @mvalentsev in #2322
New Contributors
- @kobihikri made their first contribution in #2097
- @Taylor-yuhb made their first contribution in #2123
- @seoseo-ai made their first contribution in #2139
- @marcoaperez made their first contribution in #2283
Full Changelog: v3.7.1...v3.8.0
Install: pip install -U mempalace==3.8.0
v3.7.1 — mine completeness, reconnect integrity, clean shutdown
v3.7.1 — mine completeness, reconnect integrity, clean shutdown
Post-3.7.0 integrity patch: ingest no longer hangs on non-regular files, incomplete mines can be retried instead of permanently skipped, chromadb reconnect no longer rewinds the HNSW index, and MCP releases the writer lease on SIGTERM/SIGHUP.
Bug Fixes
- Ingest commands no longer hang on a named pipe.
os.walkandgloblist a FIFO as an ordinary filename and MemPalace decides what to read from the suffix, so a pipe callednotes.mdin a mined directory wedgedminein the kernel forever: opening a FIFO for reading waits for a writer that never arrives, and theS_ISREGrefusal written on the next line could never run.mine --mode convos,sweep,init,compressandsplitblocked the same way through their own readers. The four affected opens now passO_NONBLOCK, which makes the existing type check reachable — a pipe is refused on its mode, with or without a live writer — and the discovery walks drop non-regular entries with aSKIP: <name> (not a regular file)line, so the readers that use a plainopen()never see one. Regular files read back byte-identical; the one case where the flag is not inert, a reader breaking a write lease, re-checks the file type and retries without it rather than dropping the file.mine --mode extractwas already immune through its zero-size gate. (#2221) - Project re-mine no longer silently skips a partial or interrupted file. Four related gaps in
process_file: (1) multi-batch upserts now stamp every drawer withchunk_totalsofile_already_minedcan tell "N of N committed" from "crashed after batch 1"; (2)source_mtimecomes from the samefstatas the content read, so an append between read and a later re-stat cannot permanently hide the new tail; (3) a failed stale-drawer purge aborts the file instead of half-overwriting; (4) closets are purged even when the re-mine ends with zero drawers. A mid-file upsert failure also deletes the partial drawers and closets for that source before re-raising, so the next mine retries instead of treating the incomplete set as complete. (#2088, #2122, #2151) - Conversation mine completeness matches the project path. Convo drawers now stamp
chunk_total; a mid-batch upsert failure deletes that source's partial drawers before re-raising;prefetch_mined_setomits incomplete groups so the bulk "already filed" skip cannot permanently strand missing exchanges from an interrupted transcript mine. (#2183) - Stale chromadb System cache is cleared on palace reconnect. After a peer or rebuild changes
chroma.sqlite3on disk, bothmcp_server._get_clientandChromaBackend._clientdrop chromadb's path-keyedSharedSystemClientcache before reopening — otherwise the stale in-memory HNSW segment is reused and can persist an outdated index over the peer's writes (index count going backwards). (#2002, #2028, #2026, #2032) - MCP releases the palace writer lease on SIGTERM/SIGHUP. The lease was only released via
atexit, which CPython skips on those signals' default disposition. SSH disconnect (SIGHUP) and container/systemd stop (SIGTERM) therefore leftmine_palace_*.locknaming a dead PID until a contender's liveness check reclaimed it.main()now installs handlers that exit throughsys.exit, so the existingatexitrelease path runs. (#2205)
A big thank-you to everyone who contributed to this release. Contributors and first-time contributors are credited below.
What's Changed
- fix(tests): harden hybrid search against empty Windows Chroma reads by @igorls in #2220
- docs(changelog): lead 3.7.0 with agent logstream + tighten notes by @igorls in #2219
- fix: 3.7.1 critical patch — hang, re-mine honesty, stale Chroma cache by @igorls in #2228
- fix(mcp_server): reset chromadb System cache on staleness reconnect (#2002) by @colorpanda82 in #2026
- fix(chroma): reset chromadb System cache in ChromaBackend._client() on inode/mtime reopen by @colorpanda82 in #2032
- fix(miner): close four re-mine safety gaps in process_file by @KeilerHirsch in #2088
- chore(release): 3.7.1 by @igorls in #2238
- chore: merge main into develop after 3.7.0 promotion by @igorls in #2242
- Release v3.7.1 — promote develop to main by @igorls in #2241
New Contributors
- @colorpanda82 made their first contribution in #2026
Full Changelog: v3.7.0...v3.7.1
Install: pip install -U mempalace==3.7.1
v3.7.0 — agent logstream, integrity spine, and pluggable embeddings
v3.7.0 — agent logstream, integrity spine, and pluggable embeddings
The headline of this release is agent logstream coordination: an append-only, local-first event layer so agents on different machines can delegate work, wait for replies, exchange patches, and acknowledge handoffs through the MemPalace hub — without a human relaying messages. Everything else in 3.7.0 hardens long-lived palaces under multi-session load (single-writer ownership, safer repair/re-mine, MCP lifecycle) and expands embed/search options (OpenAI-compatible embeddings, search date windows) without changing the local-first default.
Features
-
Agent logstream coordination (RFC 003). Append-only event layer for multi-agent work: durable task packets, wait/ack handoffs, patch and file artifacts, and live tailing over the MCP HTTP hub (
GET /logstream/streamSSE). MCP tools includemempalace_event_append/list/wait/ack, artifact put/get, and patch submit; CLImempalace logstreammirrors the core verbs. Events and artifacts stay local, verbatim, and separate from the drawer palace (logstream.sqlite3). Shared-brain / multi-machine agent fleets no longer need a human to relay status between hosts. (#2162, phases 1–5) -
Logstream multi-master sync foundation (RFC 004 step 0). Estate-level logstream replication hooks so coordinated agents can share the coordination layer across palace replicas — the storage step for a replicated shared brain. (#2162, logsync)
-
OpenAI-compatible embeddings. Opt-in
embedding_model: "openai-compat"talks to any/v1/embeddingsendpoint (LM Studio, llama.cpp, vLLM, Ollama's OpenAI shim, or a self-hosted server) over stdliburllib— no new dependency. Config and env vars set URL, model, and key; the model id is part of the embedder name so a model change forces a reindex. Default MiniLM/ONNX path is unchanged. (#1671, #1559) -
Search date window.
mempalace_searchandmempalace searchacceptsince/before([since, before)onfiled_at), shared withlist_drawersviamempalace.date_window. Undated drawers are excluded while a bound is active; the vector candidate pool widens under a filter and reports truncation when the pool is full. (#2000, #463) -
Hermes memory provider (core). In-package Hermes
MemoryProviderfiles live turns throughfile_conversation_exchange()so metadata matches convo mining, with a background worker so the agent loop never blocks. Install/backfill/docs remain a stacked follow-up. (#1915, #2215) -
RFC 002 source adapters on mine.
mempalace mine <source> --source <adapter>resolves registered adapters, holds the palace writer lease for the full ingest, and keeps dry-runs inert. Legacy--modepaths are unchanged. (#2068, #2062) -
Hook write-routing through the daemon. Background hook saves and mines can honor the shared write-routing policy so multi-session setups serialize mutations through one local owner. (#2030, #1963)
Performance
-
EmbeddingGemma groups documents by size before sub-batching, cutting padded-token work on long sweeps without changing vector meaning. Applies only to
embedding_model: embeddinggemma. (#2104) -
HNSW capacity probes are cached and invalidated by palace file signature, so repeated status/taxonomy paths no longer re-scan native segments every call. (#2051, #1471)
-
chunk_textline numbering is O(N), fixing multi-second hangs on large sources. (#2054, #2055)
Bug Fixes
-
Mining works again on the default Chroma backend. Explicit-embedding writes no longer hand Chroma
np.float32scalars thatnormalize_embeddingsrejects. (#2187) -
ChatGPT data exports are parsed as conversations, not stored as raw JSON arrays. (#2160)
-
Local backends enforce process-lifetime single-writer ownership. File-backed palaces require one writer owner for the process lifetime; read-only MCP may coexist; remote backends remain multi-process. (#2079, #2045)
-
MCP refuses writes when the served library drifts (mempalace, and chromadb when that backend is active) after an upgrade without restart. Opt out with
MEMPALACE_MCP_ALLOW_STALE_LIBRARY. (#2081, #899) -
Chroma HNSW write defaults match chromadb (
batch_size=100/sync_threshold=1000), retiring the old 2/2 bloat guard. (#2107, #2106) -
Repair and recovery are safer under contention. Mine-lock before archive, preserve temp collections on failed swap, fail loud on truncated pagination; dry-run is a true preview in both legacy and from-sqlite modes; backups skip sockets/pipes/device nodes so a live palace socket no longer aborts repair/migrate. (#2109, #2086, #2087, #2133, #2144, #2207, #2212)
-
rebuild_indexholds the palace writer lease for the full snapshot→rebuild/swap cycle. (#2195) -
Orphaned per-source mine locks are reaped (age + nonblocking flock), throttled to once per 15 minutes; palace-level locks are untouched. (#2200)
-
HNSW divergence is preflighted before remaining
count()crash sites across mine, dedup, migrate, repair, and palace helpers. (#2093) -
Re-mine and conversation ingest no longer lose or duplicate drawers. Content-hash dedup, sweeper purge scope, round-trippable
drawer_idon search; Claude Codesubagents/skipped by default (--include-subagentsto opt in). (#2050, #2125, #2090, #1330, #1217) -
MCP and daemon lifecycle harden multi-agent use. Read-only refuses config/checkpoint-ack host mutations; stdio exits on EOF; daemon defers lock-refused jobs; Windows stdout capture falls back or fails closed if the protocol stream cannot be restored. (#2126, #2072, #2029, #2211, #2210)
-
Encoding and Windows locale hardening. Pin UTF-8 on config/dialect opens; mojibake repair no longer destroys clean Portuguese/Vietnamese/Turkish prose; repair-encoding CLI reconfigures stdio; non-ASCII CLI symbols replaced for GBK consoles. (#2098, #2208, #2194, #1104, #1034, #2193)
-
Small correctness fixes. Entity-candidate ReDoS guard; reject pathological
chunk_overlap; worktree cwd maps to the project wing; markdown emphasis is not emotion; service entrypoints restoreMEMPALACE_PALACE_PATH; systemdRestart=alwayswith idle watchdog docs; validdocker-compose.ymlenvironment key. (#2127, #2056, #2206, #2199, #2192, #2203, #2204, #2188)
Documentation
- Agent logstream concept page, coordination protocol, shared-brain fleet guide, and RFC 003/004. (#2162)
- Operator write-routing / single-writer recovery notes. (#2079)
- Remote-server idle watchdog and read-only semantics. (#2126, #2204)
- README Docker section leads with the published image and real mount/permission pitfalls. (#2196)
- MX3 public-shim example and CONTRIBUTING Discussions cleanup. (#597, #555)
Internal
- Docker publish is gated on a real smoke script (Compose parse, mine, MCP handshake). (#2189)
- Embedding empty-batch / plain-sequence regression tests; HNSW defaults assertions. (#2191, #2159)
A big thank-you to everyone who contributed to this release. Contributors and first-time contributors are credited below.
What's Changed
- fix(miner): reject chunk_overlap above half the chunk size to stop chunk_text hang (#2056) by @mvalentsev in #2058
- perf(miner): O(N) incremental line-number tally in chunk_text (#2054) by @mvalentsev in #2055
- feat(hooks): apply shared daemon write-routing policy by @fatkobra in #2030
- perf(mcp): cache the HNSW capacity probe, invalidated by file signature (#1471) by @mvalentsev in #2051
- fix(storage): enforce local single-writer ownership by @igorls in #2079
- fix(repair): take the mine-lock before archiving in repair --mode from-sqlite by @joshuafontany in #2109
- fix(chroma): adopt chromadb's own HNSW write defaults by @joshuafontany in #2107
- fix: preflight HNSW divergence before every col.count() call site the audit found by @KeilerHirsch in #2093
- fix(repair): stop dropping drawers with zero embedding_metadata rows by @KeilerHirsch in #2087
- fix(repair): preserve verified temp copy on failed rebuild swap; fail loud on truncated pagination by @KeilerHirsch in #2086
- fix: prevent duplicate drawers when re-mining LLM conversations by @rohanprichard in #2050
- fix(search): return round-trippable drawer IDs by @fatkobra in #2090
- fix(convo_miner): stop sweeper drawers being purged (#2089) by @igorls in #2125
- fix(mcp): self-exit on stdin EOF/broken pipe so orphaned stdio sessions release locks by @xcarbo in #2072
- fix(daemon): defer jobs refused the palace lock, don't fail them (#2014) by @mvalentsev in #2029
- fix(mcp): refuse config and ack writes in read-only mode (#2103) by @igorls in #2126
- fix(mcp): refuse config and ack writes in read-only mode (#2101) by @mvalentsev in #2103
- fix(entity): defuse entity-candidate ReDoS on long ASCII runs (#2065) by @igorls in #2127
- chore(release): 3.7.0 by @igorls in #2128
- fix: release 3.7.0 polish — WAL reopen, search errors, hash stamp by @igorls in #2130
- fix(repair): honor --dry-run for repair --mode from-sqlite (#2133) by @igorls in #2138
- fix(convos): honor mined state ...
v3.6.0
v3.6.0 — secure remote serving, temporal facts, and resilient recovery
This release makes MemPalace substantially easier to operate beyond a single local process while tightening the guarantees that protect long-lived palaces. A new secure-by-default mempalace serve path supports authenticated remote and team deployments with TLS and read-only enforcement; an opt-in Milvus backend adds embedded, self-hosted, and managed storage choices; and atomic knowledge-graph supersession gives changing facts precise temporal boundaries. Conversation chronology, mined-session graph derivation, project exclusions, and LaTeX coverage deepen ingestion, while startup, metadata, and recovery work make large palaces faster and safer. The MCP surface now comprises 36 tools.
Features
- Turnkey secure remote / team server.
mempalace serveexposes the full MCP surface over HTTP with secure defaults: non-loopback binds require a bearer token, generated tokens are stored with restrictive permissions and passed through the child environment rather than argv, native TLS 1.2+ is supported, and--read-onlyboth hides and refuses mutating tools. Docker Compose, systemd, and environment templates are included. (#1877, #1897, #1900) - Milvus storage backend. The new opt-in
milvusbackend supports Milvus Lite, self-hosted Milvus, and Zilliz Cloud, with COSINE vector search, native BM25 lexical search for new collections, namespace isolation, target-mismatch protection, and an optional dependency extra. (#1899) - Atomic knowledge-graph fact replacement.
supersede()/mempalace_kg_supersedecloses an open fact and opens its successor at one shared instant. Temporal queries use half-open intervals at timestamp precision while preserving whole-day semantics for date-only facts. (#1913) - Conversation chronology is preserved. Drawers retain transcript time as
authored_at, search results expose it, exact hybrid-score ties prefer recently authored content, and an idempotent dry-run-first backfill updates existing palaces without re-embedding.mempalace_list_drawersalso gainssince/beforebounds. (#1890, #1891) - Mined sessions populate the associative graph. A precision-biased structural extractor records code symbols, URLs, paths, and qualified identifiers as drawer entities; conversation mining derives hallways from them, exposed by the new
mempalace hallwaysCLI command. (#1894, #1895) - Per-project mining exclusions through
exclude_patternsinmempalace.yaml, without changing corrected--limitsemantics. (#1213, #1953) - LaTeX project coverage for
.texand.bibprose sources. (#1901) - Shared daemon write-routing policy provides one consistent policy seam for routing write-capable clients toward the local daemon. (#2027)
- Checkpoint author attribution now preserves the filing agent instead of hard-coding every checkpoint drawer as
checkpoint. (#2023, #2034)
Performance
- MCP initialization no longer waits for palace-wide integrity work. stdio answers
initializeimmediately while startup preflight runs in the background; concurrent tools join the same verdict instead of duplicating work. Large-palace startup SQLite probes are bounded, while repair preflights remain strict. (#1911, #1987) - Qdrant metadata counts use server-side facets instead of fetching and tallying every record; the embedding wrapper forwards facet and bulk-metadata capabilities correctly. (#1868, #1898)
- pgvector metadata-only fetches omit document payloads, reducing transfer and decoding work. (#1892)
Bug Fixes
- Chroma recovery distinguishes derived-index damage from data loss. Valid all-layer-0 HNSW segments are no longer quarantined repeatedly; isolated FTS5 corruption is rebuilt from intact content during repair and after mining; embedded NUL bytes are sanitized before reaching ChromaDB. (#1716, #1872, #1878, #1927, #1928)
- SQLite recovery is bounded, atomic, and honest. Integrity checks wait out transient writer contention; recovery archives use atomic rename;
repair --mode from-sqliterebuilds FTS5, vacuums, and requires a clean finalPRAGMA quick_check; cleanup failures return non-zero instead of printing false success. (#1945, #2015, #2017) - CLI search checks HNSW divergence before opening ChromaDB, routing damaged palaces directly to SQLite BM25 while leaving healthy and non-Chroma backends on their normal path. (#2016)
- Writer leases recover instead of stranding servers read-only. Refused writers retry and promote after a peer exits; status cannot acquire the writer lease; re-entrant holders are released across interruption;
checkpointanddelete_by_sourceare correctly classified as mutations. (#1923, #1930, #1934, #1960, #1970, #1971) - Status reports only checks that actually ran. Non-Chroma backends mark Chroma SQLite integrity as not applicable. (#1931, #1946)
- Conversation transcripts are treated as mutable. Appended or rewritten sessions are purged and re-filed by modification time, while Claude Code
tool-results/sidecars are excluded from scans. (#1957, #2010) - Explicit palace selection scopes derived graph state so mining hallways and tunnels remain beside the selected
--palace. (#2018) - Remote and local server hardening. Non-loopback HTTP requires a token unless explicitly overridden; provider probes cannot reuse ambient external keys before selection; hook transcript and file-copy/repair paths receive stricter validation; importing MCP no longer clobbers root logging; HTTP writes re-enter the palace lock safely; routine disconnects no longer emit tracebacks. (#1859, #1860, #1864, #1885, #2003, #2004)
- Mining and configuration correctness. Oversized files warn visibly, configured
~paths expand consistently, wing slugs handle special characters, and Windows background processes avoid console flashes. (#923, #1852, #1857, #1863, #1865) - Windows
.gitignorehandling uses UTF-8 explicitly, avoiding locale-dependent failures. (#1648) - L1 wake-up prefers the latest moments when importance ties. (#1630)
- Backend detection requires a SQLite magic header, preventing unrelated files from being mistaken for a palace. (#1893, #1896)
Documentation
- Added a storage-backend configuration reference, a remote/team-server deployment guide,
authored_atmigration guidance, and refreshed the OpenClaw integration for the full 36-tool MCP surface. (#1719, #1877, #1890, #1904, #1905)
Internal
- Expanded WAL crash-safety, idempotence, and redaction-path coverage; updated GitHub Actions and Ruff; repaired
uv.lockdrift for Ruff 0.15.20 and Python 3.9 dependency markers. (#1869)
A big thank-you to everyone who contributed to this release. Contributors and first-time contributors are credited below.
What's Changed
- fix: tighten local guards and file handling by @igorls in #1864
- test(wal): cover WAL crash-safety, idempotent setup, and redaction edge paths by @arnoldwender in #1869
- fix: spawn daemon with CREATE_NO_WINDOW to match hook miner (#1783) by @eldar702 in #1857
- fix(cli): add repair rebuild-index alias by @jsiu93 in #1670
- Fix/wing slug special chars by @tp9imka in #1852
- fix(hooks): hide conhost window on Windows in _mine_sync non-daemon path by @davidfi01 in #1863
- fix: expand tilde in palace_path when read from config file by @joesebastian6079 in #1865
- fix(chroma): stop quarantining valid all-layer-0 HNSW segments (#1716) by @igorls in #1872
- fix(repair): auto-heal isolated FTS5 inverted-index corruption (#1596) by @igorls in #1878
- fix(mcp): stop clobbering host app root logger at import (#1860) by @mvalentsev in #1885
- fix(layers): order L1 wake-up by recency (filed_at) so it surfaces the latest moments by @davidglidden in #1630
- fix(cli): force UTF-8 when reading/writing .gitignore in init by @ALaDingAhmad in #1648
- chore(deps): bump actions/checkout from 6 to 7 by @dependabot[bot] in #1882
- chore(deps): bump docker/setup-qemu-action from 3 to 4 by @dependabot[bot] in #1880
- chore(deps): bump docker/setup-buildx-action from 3 to 4 by @dependabot[bot] in #1881
- chore(deps-dev): bump ruff from 0.15.18 to 0.15.20 by @dependabot[bot] in #1883
- fix(backends): require SQLite magic header for chroma + sqlite_exact detect() (#1893) by @messelink in #1896
- fix(pgvector): skip document column for metadata-only fetches (#1840 follow-up) by @messelink in #1892
- feat(convo): preserve authored timestamp from transcripts by @JosefAschauer in #1890
- fix(palace): process-wide mine_palace_lock re-entrancy so the HTTP transport can write by @trongnguyenbinh in #1859
- feat(mcp): add since/before date filter to list_drawers (#1128) by @mvalentsev in #1891
- feat: optimize metadata counting using Qdrant server-side facets by @Prayaksh in #1868
- feat(graph): auto-populate the associative graph from mined sessions by @JosefAschauer in #1895
- docs(guide): Remote / Team Server deployment g...
v3.5.0
v3.5.0 — local write daemon, opt-in HTTP transport, and palace-cleanup tooling
This cycle adds two new ways to run MemPalace's write path and a set of tools for keeping a palace clean. An opt-in local daemon serializes background mines, diary saves, and hook ingests through a single process instead of racing for the palace handle, and an opt-in HTTP transport lets the MCP server run behind a long-lived HTTP client/proxy — loopback-default, with a Host/Origin DNS-rebinding guard and an optional bearer token. Three new MCP tools land alongside: mempalace_checkpoint (batch a whole session into one save), mempalace_delete_by_source (surgically purge mined benchmark/eval contamination — drawers and their index entries), and a source_file filter for scoped search. New transcript parsers (Continue.dev, Gemini CLI, Pi) and miner coverage for C#/PHP/Swift/Kotlin/Java widen what you can mine, and a batch of large-palace performance and reliability fixes round out the release.
Features
- Opt-in local daemon for queued writes.
mempalace daemonserializes all palace writes through one local process so background work stops racing the palace handle. Opt-in and local-only. (#1826) - Opt-in HTTP transport for the MCP server.
mempalace-mcp --transport httpserves JSON-RPC atPOST /mcp(withGET /healthz) for proxy/long-lived deployments. stdio remains the default; the HTTP path binds127.0.0.1, pinsHostand rejects non-loopbackOrigin(DNS-rebinding guard), and supports an optionalMEMPALACE_MCP_HTTP_TOKENbearer token. (#1801, #1806) mempalace_checkpointbatch-save tool. Files multipleadd_drawercalls plus an optional diary entry in a single MCP round-trip, verbatim, reusing the idempotent add/dedup path. (#1851)mempalace_delete_by_sourcebulk-cleanup tool. Exact-match, dry-run-by-default deletion of every drawer and its closet/AAAK index entries for asource_file— the recourse when benchmark/eval files get mined into a real wing. The dry run reports the blast radius; the commit writes a WAL audit entry. (#1722, #1729)- Optional
source_filefilter formempalace_search. Scope a search to an exact stored path; threaded through every search path so it never silently drops a match. (#1815, #1817) - New transcript parsers — Continue.dev sessions (#731), Gemini CLI / AI Studio (#204), and Pi agent JSONL (#169).
- Wider miner language coverage — C#/.NET, PHP (#1819), Swift/Kotlin (#1368), and Java project detection incl. rootless subprojects (#1720).
- Final mine on Claude plugin
SessionEndso the last exchanges are captured at session close. (#1814, #1820)
Performance
- Overview/status and
graph_statsanswered from the SQLite aggregate — fixes large-palace timeouts. (#1748, #1379) - Embedder caps ONNX-runtime intra-op threads so a background mine no longer pins every core. (#1068)
- SQL-pushdown pagination for
sqlite_exact(#1842) andpgvector(#1840), plus single-scroll bulk metadata for Qdrant (#1832).
Bug Fixes
- pgvector tolerates hostile transcript bytes — a lone surrogate (#1833) or NUL byte (#1829) no longer aborts the whole mine.
- Diverged-index recovery points at
repair --mode from-sqlite, not a re-mine — re-mining silently dropped MCP-added drawers and diary entries. (#1843, #1847, #1849) - Stale ChromaDB HNSW divergence routes to the SQLite fallback instead of failing the read. (#1816, #1822)
- The MCP server refuses a second writer for the same palace rather than racing the HNSW handle. (#1818, #1823)
- Windows hook miner spawns with
CREATE_NO_WINDOW— no console flash. (#1783, #1848) - Percent-encoded SQLite read-only URIs so spaced/special-char palace paths open.
CI
test-windowsretries only the transient ChromaDB HNSW compaction flake (--only-rerun); Linux/macOS keep zero reruns so real regressions stay loud. (#1854)
A big thank-you to everyone who contributed this cycle — many of these features and fixes came from the community, including several first-time contributors. Everyone is credited below.
What's Changed
- fix(migrate): roll back swap from pre-migrate backup on failure by @eldar702 in #1028
- feat(miner): add PHP ecosystem file extensions by @ManuelReschke in #1819
- feat(miner): add support for Swift and Kotlin file extensions by @EVSalomon in #1368
- fix: detect Java project manifests by @jsiu93 in #1720
- feat(normalize): add Continue.dev session parser by @sjhddh in #731
- feat: add Gemini CLI / AI Studio session import support by @FBISiri in #204
- feat: add Pi agent JSONL session normalizer by @adv3nt3 in #169
- feat(miner): add C# and .NET file extensions to READABLE_EXTENSIONS by @Davez69gto in #952
- feat: opt-in local daemon for queued MemPalace writes by @igorls in #1826
- fix(daemon): address post-merge review feedback on #1826 by @igorls in #1828
- chore(deps-dev): bump ruff from 0.15.15 to 0.15.18 by @dependabot[bot] in #1827
- perf: sqlite fast-path for overview tools + embedder thread cap (#1748, #1379, #1068) by @igorls in #1836
- perf(mcp): sqlite fast path for graph_stats (#1379) by @igorls in #1837
- fix: percent-encode sqlite read-only URIs for spaced/special-char paths by @igorls in #1838
- fix(pgvector): strip NUL bytes so a transcript NUL no longer aborts the mine (#1829) by @mvalentsev in #1831
- fix(pgvector): replace lone surrogates so a transcript surrogate no longer aborts the mine (#1833) by @mvalentsev in #1834
- fix(mcp): route _sqlite_graph_stats through sqlite_read_uri by @igorls in #1839
- fix(backends): push sqlite_exact get(limit, offset) pagination into SQL (#1841) by @mvalentsev in #1842
- fix(pgvector): push get(limit, offset) pagination into SQL (#1830) by @mvalentsev in #1840
- test(backends): live-substrate conformance module for pgvector by @jphein in #1769
- fix(tests): run fact_checker main via subprocess to clear runpy warning by @trek-e in #1798
- fix: use CREATE_NO_WINDOW so Windows hook miner spawns don't flash a console (#1783) by @eldar702 in #1848
- fix(chroma): route stale hnsw divergence to sqlite fallback by @fatkobra in #1822
- fix(repair): point index-read failures to repair --mode from-sqlite (#1843) by @mvalentsev in #1847
- fix: point diverged-index recovery at from-sqlite, not re-mine (#1843) by @undeadindustries in #1849
- chore(deps): bump docker/login-action from 3 to 4 by @dependabot[bot] in #1788
- chore(deps): bump docker/build-push-action from 6 to 7 by @dependabot[bot] in #1787
- chore(deps): bump docker/metadata-action from 5 to 6 by @dependabot[bot] in #1786
- fix(backends): single-scroll bulk metadata fetch for Qdrant; bump scroll page size (#1796) by @fatkobra in #1832
- fix(mcp): refuse second writer for same palace by @fatkobra in #1823
- feat(search): add an optional source_file filter to mempalace_search (#1815) by @mvalentsev in #1817
- feat: add mempalace_checkpoint batch save tool by @undeadindustries in #1851
- fix(claude-plugin): run final mine on SessionEnd by @fatkobra in #1820
- feat(mcp): add mempalace_delete_by_source bulk-cleanup tool (#1722) by @arnoldwender in #1729
- feat(mcp): add opt-in HTTP transport by @fatkobra in #1806
- ci(test-windows): retry the transient ChromaDB HNSW compaction flake by @igorls in #1854
- chore(release): 3.5.0 by @igorls in #1853
- Release v3.5.0 — promote develop to main by @igorls in #1855
New Contributors
- @ManuelReschke made their first contribution in #1819
- @EVSalomon made their first contribution in #1368
- @jsiu93 made their first contribution in #1720
- @FBISiri made their first contribution in #204
- @Davez69gto made their first contribution in #952
Full Changelog: v3.4.1...v3.5.0
v3.4.1
v3.4.1 — Cursor and Antigravity IDE support
We now have support for two more editors: a Cursor plugin with native hooks, and first-class Google Antigravity support — both bringing MemPalace's auto-save, session-start recall, and verbatim transcript mining to the same standard already shipping for Claude Code and Codex. Two reliability fixes round out the cycle: embeddinggemma no longer OOM-kills large re-embeds, and migrate / repair backups stop accumulating until they fill the disk.
Features
-
Cursor IDE plugin (
.cursor-plugin/). Auto-registers themempalace-mcpserver, five slash commands (/mempalace-help,/mempalace-init,/mempalace-mine,/mempalace-search,/mempalace-status), and a model-invocable skill — no manual~/.cursor/mcp.jsonedit. Install from a local clone now, or the Cursor marketplace once published. (#1632) -
Cursor IDE hooks (
stop/preCompact/sessionStart). Background auto-save every N agent turns, synchronous transcript mining before Cursor compacts, and session-start memory recall scoped to the workspace wing. One-command installer athooks/cursor/install.sh(--scope user|project,--variant full|minimal,--dry-run,--uninstall) — idempotent and dependency-free. -
First-class Antigravity (Google) IDE support. New
.antigravity-plugin/package and idempotent installer that registers MemPalace as an Antigravity plugin — MCP server, skill, and two lifecycle hooks (background mining onStop, verbatim memory injection on the first model call). bash 3.2 / macOS-compatible, shares the same~/.mempalace/hook_state/directory as the Claude Code / Codex / Cursor hooks, and honors every existing kill switch. (#1633, #1771) -
Zero-config interpreter resolution for hooks. The hooks now resolve Python from the
mempalace-mcpconsole-script shebang before falling back topython3, fixing silently-no-op mining underuv tool install/pipxlayouts where the systempython3can't importmempalace.
Bug Fixes
-
embeddinggemmano longer OOM-kills bulk re-embeds. The ONNX embedder ran a single pass over its entire input, so a repair-scale batch (~5,000 docs) allocated attention buffers far beyond available RAM and the kernel killed the process silently. Embedding now runs in 32-doc sub-batches; per-document vectors are unchanged. (#1770) -
Backup retention to prevent unbounded disk usage.
mempalace migrateandmempalace repair max-seq-idwrote a fresh, full-size backup every run and never cleaned up — one palace was found with hundreds of GB of stale backups beside a few hundred MB of live data. A newmax_backupssetting (default10;0keeps all) now prunes the oldest after each new backup is written. (#1697)
A big thank-you to everyone who contributed this cycle — both IDE integrations and several of these fixes came from the community, including a number of first-time contributors. Everyone is credited below.
What's Changed
- feat(searcher): metric-aware distance→similarity conversion (RFC 001 §10) by @igorls in #1727
- feat(backends): embedder-identity contract + three-state enforcement (RFC 001) by @igorls in #1731
- feat(backends): observable maintenance hooks + pgvector indexed-build path (RFC 001) by @igorls in #1732
- feat(backends): shared embedder-identity sidecar + qdrant identity (RFC 001) by @igorls in #1734
- fix(backends): keep post-deletion dim-None HNSW segments instead of quarantining (#1710) by @mvalentsev in #1723
- fix(backups): add max_backups retention to bound backup disk usage by @margaretjgu in #1697
- feat(mcp): add mempalace_mine tool (#1662) by @mvalentsev in #1692
- fix(miner): count only new work toward --limit, not already-mined skips (#1535) by @mvalentsev in #1622
- feat(mcp): expose list_hallways and delete_hallway tools by @ggettert in #1741
- fix(mcp): preserve room/wing casing on case-only update by @Sathvik-1007 in #1737
- feat: add Antigravity IDE support (hooks, plugin, skill, docs, tests) by @undeadindustries in #1633
- feat(antigravity): add recall skill, optional rule, shared protocol by @undeadindustries in #1771
- feat: add Cursor IDE support (hooks, plugin, skill, docs, tests) by @undeadindustries in #1632
- fix(backends): serialize first connect in sqlite_exact and pgvector (#1774, #1775) by @mvalentsev in #1793
- fix(mcp): treat chunked drawers as logical drawers by @fatkobra in #1782
- fix(repair): run post-rebuild FTS5 cleanup on legacy cmd_repair path (#1747) by @mvalentsev in #1749
- fix(embedding): chunk EmbeddinggemmaONNX batches to bound ONNX memory (#1770) by @mvalentsev in #1777
- fix(hooks): delegate shell hooks to Python runner by @fatkobra in #1790
- fix(ids): use length-prefixed recipe v3 by @fatkobra in #1781
- fix(hallways): scope hallway-file path to MempalaceConfig.palace_path (#1778) by @ggettert in #1780
- fix(searcher): scope neighbor expansion by parent_drawer_id (#1580) by @mvalentsev in #1582
- fix(mcp): drop top-level anyOf from diary_write schema by @Hexecu in #1717
- test: stabilize release validation on develop by @igorls in #1802
- fix(mcp): fail closed when add_drawer idempotency pre-check fails by @thismilktea in #1721
- fix: close blob seq sqlite migration connection by @igorls in #1804
- fix: preserve collection_name on MCP search retry by @trek-e in #1624
- fix(palace): clean source mine locks safely by @igorls in #1803
- test: stabilize closet boost fixture on Windows by @igorls in #1807
- chore(release): 3.4.1 by @igorls in #1809
- fix(hooks): portable mtime in macOS hook throttles; doc cleanup by @igorls in #1811
- Release v3.4.1 — promote develop to main by @igorls in #1810
New Contributors
- @margaretjgu made their first contribution in #1697
- @ggettert made their first contribution in #1741
- @undeadindustries made their first contribution in #1633
- @Hexecu made their first contribution in #1717
- @thismilktea made their first contribution in #1721
Full Changelog: v3.4.0...v3.4.1
v3.4.0
v3.4.0 — pluggable backends, Docker, and reliability fixes
Features
- Pluggable vector backends — Qdrant, pgvector, and sqlite_exact alongside the default ChromaDB, selectable via
MEMPALACE_BACKEND/--backend. - Docker images (CPU + GPU) for the MCP server and CLI.
mempalace migrate-wings— one-time migration that normalizes legacy wing names (strip leading/trailing separators) so pre-upgrade palaces stay discoverable. Seedocs/recovery/wing-name-migration.md.- Known-systems lexicon keeps multi-word product names atomic in entity detection.
Fixes
- embeddinggemma (the default model) now works with ChromaDB 1.5.x — semantic search was silently failing on fresh installs.
- Prevent silent data loss from
drawer_idhash collisions. - Importing
mcp_serverno longer recreates~/.mempalace(respects the privacy kill-switch). diary_writeaccepts acontentalias and restores the missing-parameter diagnostic.- Explicit-vector backends handle single-document inputs correctly.
Infrastructure
- PyPI publishing via GitHub Actions Trusted Publishing (OIDC), gated by manual approval.
v3.3.6 — multilingual recall, living graph, surgical reads
3.3.6 is a features release. The cycle's headline work: multilingual recall by default (embeddinggemma replaces MiniLM, cross-lingual cosine jumps from 0.35 → 0.88), the first cut of the living-memory graph (hallways within wings, tunnels across wings, Hebbian potentiation + Ebbinghaus decay so connections strengthen with use and fade without), office-document mining (PDF, DOCX, PPTX, XLSX, RTF, EPUB via the new --mode extract), virtual line numbers + surgical closet pointers that cite exact line ranges on exact dates, and the entity-detection cleanup pass that keeps "Code" out of your hallways and "Claude Code" atomic.
The promises haven't moved. Every word stored exactly. Everything stays on your machine. No telemetry. Each release sharpens what's already there.
Features
-
Office-document mining via
--mode extract. Newmempalace mine <dir> --mode extractingests PDFs, Word (.docx), PowerPoint (.pptx), Excel (.xlsx), RTF, and EPUB books in addition to the existing source-code/text path. Install withpip install mempalace[extract]— pullsstriprtffor RTF and MarkItDown (with[docx,pdf,pptx,xlsx]sub-extras) for the binary formats. Python 3.9 users get RTF coverage only because MarkItDown requires 3.10+. Drawers from the extract path carryextract_modemetadata so the convo miner's "already mined?" check and drawer-id generation stay isolated per mode (#1528). (#1555) -
Virtual line numbers + surgical closet pointers. Stored drawers now carry virtual line numbers so the read CLI verb and closet pointers can cite exact line ranges. Closet pointers (Tier 6a) include date+line-range information derived from filename and content-body date parsing (
python-dateutilis now a core dep), so MemPalace can point you to exact lines on exact dates rather than just "somewhere in this drawer." (#1555, #1584) -
Within-wing hallways. When two entities (people, projects, topics) co-occur in the same drawer, the miner now records a "hallway" — a graph edge connecting them inside that wing. Computed automatically as part of the post-mine step in
compute_hallways_for_wingso the graph grows incrementally with new content, no separate command. Foundation for cross-room entity navigation inside one palace. (#1558, #1560) -
Cross-wing tunnels promoted from hallways. When the same entity appears in hallways across multiple wings, MemPalace now automatically promotes that into a tunnel — letting queries hop from one person's wing to a project wing they appear in, without anyone calling
create_tunnelmanually. Topic tunnels from the existingcompute_topic_tunnelspath remain unchanged. (#1565) -
Living-memory dynamics (Hebbian potentiation + Ebbinghaus decay). Hallways and tunnels get stronger every time the same connection is reinforced by new content ("what fires together wires together") and fade gradually if a connection stops appearing in incoming drawers. Navigation weights track real palace usage instead of being static, so retrieval ranking improves over time as the palace is actually used. (#1578)
-
API-tool transcripts auto-route to
wing_api. Conversation transcripts from API-style AI tools (Claude Code, Claude.ai, ChatGPT, Slack-bot exports, generic OpenAI-shape JSON, etc.) now route into a dedicatedwing_apiinstead of mixing into the human-conversation wings. Keeps tool-call traffic from polluting personal/project wings and improves search precision when you're looking for "what did I say" vs. "what did the agent say." (#1236) -
Multilingual embedding by default for new installs:
embeddinggemma-300mONNX (q8, MRL→384-dim). MemPalace's previous embedder (all-MiniLM-L6-v2) is trained English-only — cross-lingual cosine similarity on parallel-translated text averages 0.35 across DE/FR/HI/IT/KO/RU (RU at 0.17, near-orthogonal). A Russian-speaking user effectively cannot find their own memories, which breaks the "100% recall" design promise from CLAUDE.md. NewEmbeddinggemmaONNXclass inmempalace/embedding.pybrings this to 0.88 average (validated lossless vs the Ollama gguf via direct ONNX-runtime test). Lazy-downloadsonnx-community/embeddinggemma-300m-ONNX(~300 MB) on first use viahuggingface_hub. Output is truncated to 384 dims via Matryoshka Representation Learning so the model is a drop-in for ChromaDB's 384-dim collections — no schema change. Sim prefix ("task: sentence similarity | query: ") is applied automatically.Onboarding (
python -m mempalace.onboarding) now offers the multilingual model as the default — choosing it writesembedding_model: embeddinggemmatoconfig.jsonso subsequent runs pick it up without re-prompting. Existing installs that never set the env var or ran onboarding stay onminilm(back-compat).MEMPALACE_EMBEDDING_MODEL=minilm|embeddinggemmaoverrides both. Switching models on an existing palace requires re-embedding — runmempalace repair rebuild-indexafter the change. (#1483) -
Multilingual deps moved to core.
huggingface_hub,tokenizers, andnumpyare now required deps so the multilingual path works out of the box afterpip install mempalace. The[multilingual]extra is kept as a no-op alias for back-compat with install scripts. The 300 MB ONNX model itself is still lazy-downloaded on first use, not at install time. -
Friendlier ChromaDB EF-name-mismatch error. Switching
MEMPALACE_EMBEDDING_MODELon an existing palace without runningrebuild-indexpreviously surfaced ChromaDB's bareEmbedding function conflict: new: X vs persisted: YValueError— accurate but didn't tell users how to recover.ChromaBackend.get_collection()now wraps that error and points at both options: revert the env var, or runmempalace repair rebuild-index --palace <path>. (#1483) -
hooks.auto_savetoggle for silent-mode sessions. New config knob (and--silentCLI flag wiring through the save hook) lets users opt out of automatic diary saves onStop/PreCompact. Useful for "silent mode" sessions where you don't want every conversation captured. Default behavior is unchanged — auto-save still runs unless explicitly disabled. (#711) -
Filter common English content words from entity detection. High-frequency English content words ("system", "user", "memory", "project", "context", etc.) were getting tagged as entities by the per-drawer detector and polluting the entity registry as "people." A shipped COCA wordlist (top-N content words) is now consulted during entity classification so these get filtered before they reach the registry. Hardened against malformed JSON in the bundled wordlist. (#1605)
-
Case-insensitive entity matching at mine time. The initial palace build (
mempalace init) matched entity names case-insensitively, but the per-drawer tagger used during incremental mining did not — so the same person was tagged differently between init and ingest ("Aya" vs. "aya" became distinct entities). The incremental tagger now mirrors the case-insensitive matcher, restoring entity-tag consistency across the palace lifecycle. (#1557)
Bug Fixes
-
Silent data loss in three upsert paths. Three upsert sites (file ingest, conversation ingest, and one repair branch) were calling the embedder on unchunked content, silently truncating at the embedder's max-token limit. Long drawers landed with only their leading section indexed, breaking the "100% recall" promise on long-form content. All three now route through the chunker first so the full document is embedded and stored. (#1540, follow-up to #1539)
-
Paragraph chunker emitted oversized chunks for long paragraphs. The paragraph splitter assumed paragraphs were always shorter than
CHUNK_SIZEand emitted them whole; long paragraphs (legal text, dense technical writeups) silently exceeded the embedder's context window. The splitter now hard-caps each emitted chunk to honorCHUNK_SIZE. (#1538, fixes #1534) -
Per-file chunk cap was hardcoded and too low for large transcripts. A safety limit capped chunks per file at a value tuned for source code; mining very large conversation transcripts silently dropped the tail past that cap. Now configurable, with the default raised to cover realistic transcript sizes. (#1554, fixes #1455)
-
Hook subprocess / ChromaDB deadlock on Windows. Stop/PreCompact hooks could deadlock against an already-open ChromaDB client on Windows, leaving the host (Claude Code) stuck waiting on the hook. Three-part fix: stale-PID timeout on mine-lock reclamation, idle-exit path in the MCP server, and structured errors when the deadlock pattern is detected so the host can recover. (#1562, fixes #1552)
-
create_tunnelcorrupted hyphenated wing names. The endpoint parser split on-, so wings whose name contained a hyphen (mem-palace,my-app) were truncated mid-name and the tunnel pointed at a non-existent endpoint. Endpoint parsing now preserves the full slug. (#1529, fixes #1504) -
MCP knowledge-graph cache produced duplicate graphs for symlinked / differently-cased palace paths. Cache key was the raw path string, so
/Users/me/.mempalace/palaceand/Users/me/.mempalace/Palace(case-folded on macOS) or a symlinked alias produced two separate cachedKnowledgeGraphinstances pointing at the same SQLite file, with stale-read risk. Cache now normalizes viarealpath+normcaseso they collapse onto a single canonical key. (#1383, fixes #1372) -
Save-hook truncated hyphenated project folder names. Wing-name parser was splitting on
-and keeping only the first segment, somem-palacebecamemem. Fix preserves the full project-folder slug so hyphenated palaces stay coherent across hook invocations. (#1424, fixes #1410) -
Miner silently skipped symlinks. Users were confused about missing data after mining; the miner was skipping symlinks without surfacing it. Now logs e...
v3.3.5 — integrity, recovery, and cross-process correctness
3.3.5 is a fixes release. No new user-facing features — the cycle's energy went into data integrity, recovery, and cross-process correctness. If your palace ever hit Internal error: Error finding id after a big mine, or you had a knowledge-graph triple silently disappear into the void, or you're running on Windows / a multi-tenant host — this release is for you.
The headline fixes:
-
mempalace repair --mode from-sqliterecovers palaces stuck onapply_logs. When ChromaDB's HNSW segment writer wedges (the corruption class reported upstream and in #1308),--mode legacyand the inline repair both callCollection.count()as their first read — which is exactly the call that raises. The old failure mode was a repair printingCannot recover — palace may need to be re-mined from source fileseven though the SQLite tables were fully intact. The new mode reads(id, document, metadata)directly fromchroma.sqlite3via the metadata segment join, never opens a chromadb client against the corrupt palace, and re-upserts everything into a fresh palace under your configured embedding function. Verified end-to-end on a 52,300-row real-world corrupt palace. (#1308) -
Two silent-loss classes in the knowledge graph are now write-time errors. Triples with
valid_to < valid_fromused to be durably stored but unreachable (the temporal filter matched noas_of);add_triple()now rejects inverted intervals at write time. And date strings forwarded to SQLite are validated up front viasanitize_iso_temporal()(aliassanitize_iso_date()), which acceptsYYYY-MM-DDand canonical UTC datetimes (YYYY-MM-DDTHH:MM:SSZ/+00:00) and rejects everything else — natural-language inputs like"yesterday"no longer silently produce empty result sets. Behavior change: partial-date inputs that worked in 3.3.4 ("2026","2026-05") now error; pass a full date or canonical UTC datetime instead. (#1214, #1164, #1167, #1374, #1417) -
EntityRegistry.save()is now crash-safe. The people/projects map is months of mining data, and the old code did a non-atomicPath.write_text()— a power loss, OOM, orkill -9between truncate and full-flush would silently wipe it (the registry'sload()swallowsJSONDecodeError). Save now writes to a sibling temp file,fsyncs, andos.replace()s into place. The previous registry stays intact on any crash before the rename returns. (#1215) -
MCP
tool_searchrides through the post-bulk-mine HNSW flush window. After a CLI mine, ChromaDB's HNSW segment metadata can be unflushed for ~30-60s; wing-scoped MCP search was hittingInternal error: Error finding idfor that entire window.tool_searchnow detects this specific transient, drops both the MCP-local and shared-backend caches for the palace, sleeps 2s, and retries once. Successful retries are tagged withindex_recovered: trueso callers can observe when it fired. Partial fix for the broader #1315 cluster —tool_check_duplicateand other index-touching tools still need the same wrapper. (#1396) -
Cross-process correctness on Windows and multi-tenant hosts.
ChromaBackend.close_palace()now properly releases ChromaDB's rust-side SQLite file lock — reopening the same palace path aftershutil.rmtreeno longer fails withSQLITE_READONLY_DBMOVED. And the MCP server's_kgis no longer a module-level singleton: multi-tenant hosts rotatingMEMPALACE_PALACE_PATHbetween tool calls now hit the right SQLite file via a lazy per-path cache. (#1067, #1105, #1136, #1160) -
Windows stdio is UTF-8 across the board.
mempalace search > out.txtand piped fact_checker invocations no longer mojibake Cyrillic / CJK drawer text at the process boundary.mcp_server,hooks_cli, andcli/fact_checkerall reconfigure identically. (#1282) -
miner.detect_roomrouting fix for monorepos. The substring check was bidirectional, so any token that was a substring of a room name or vice versa matched —views/billing-page/src/Foo.test.tsxrouted to aninterviewsroom because"views" in "interviews"matched first. Now uses separator-bounded token matching (-,_,.,/). (#1004, closes #1002) -
mempalace compressno longer crashes on palaces above ~32k drawers. Drawer fetch is now paginated, mirroring the #851 fix inminer.py. (#1073, #1107)
Internal: test reliability got a pass too — tests/test_palace_locks.py and tests/test_chroma_collection_lock.py switched from fork to spawn for subprocess spawning (Python 3.13 + multi-threaded parent = deadlock under fork, and macOS forbids fork-without-exec via CoreFoundation), and several test files now wrap sqlite3.connect(...) in contextlib.closing() so connections release on the failure path too. (#1430, #1431)
The promises haven't moved. Every word stored exactly. Everything stays on your machine. No telemetry. No fallbacks to cloud APIs we didn't tell you about. Each release sharpens what's already there.
What's Changed
- fix(mcp_server): pass embedding_function= on collection reopen (#1299) by @igorls in #1303
- fix(hooks): quote plugin-root paths with spaces (#1076) by @mvalentsev in #1077
- fix(cli): cmd_compress writes to mempalace_closets (#1244) by @igorls in #1319
- fix(mcp): case-insensitive agent name in diary read/write (#1243) by @igorls in #1323
- fix(backends/chroma): wire quarantine_stale_hnsw into _client() (#1121 #1132 #1263) by @igorls in #1322
- fix(mcp): omit absolute filesystem paths from MCP tool responses by @igorls in #1325
- feat(searcher): candidate_strategy="union" — BM25 candidates joined with vector pool before hybrid rerank by @igorls in #1306
- fix(mcp): forward valid_to and source params in kg_add/kg_invalidate (#1314) by @igorls in #1320
- fix(cli): honor --palace flag in cmd_init (#1313) by @igorls in #1321
- fix(kg): reject inverted intervals in add_triple (valid_to < valid_from) by @arnoldwender in #1214
- fix(backends/chroma): release SQLite file lock on close_palace/close (#1067) by @mvalentsev in #1105
- fix(entity_registry): atomic write to prevent partial corruption on crash by @arnoldwender in #1215
- fix: paginate closet_llm col.get (#1073) by @sha2fiddy in #1107
- fix(cli, fact-checker): reconfigure stdio to UTF-8 on Windows by @mvalentsev in #1282
- fix(kg): validate ISO-8601 date formats at MCP boundary by @arnoldwender in #1167
- fix(mcp): lazy per-path KnowledgeGraph cache (#1136) by @mvalentsev in #1160
- docs(changelog): batch entries for 7 v3.3.5 fixes by @igorls in #1370
- fix: serialize ChromaCollection writes through palace lock by @imtylervo in #1162
- fix(hooks): treat absent ~/.mempalace as auto-save off by @lcatlett in #1305
- fix: add total count to tool_list_drawers pagination response by @Sathvik-1007 in #1114
- fix(mcp): force UTF-8 on stdio to fix -32000 on non-ASCII payloads (Windows) by @alonehobo in #1060
- fix: guard None metadata/doc in tool_check_duplicate and Layer1/Layer2 by @eldar702 in #1030
- fix(lint): hoist hooks_cli_mod import to top of test_hooks_cli (E402) by @igorls in #1375
- fix(searcher): clamp effective_distance to valid cosine range [0, 2] by @eldar702 in #1029
- fix(mcp): handle null JSON-RPC request payloads safely by @alpiua in #987
- fix: MCP server JSON output ensure_ascii=False for non-ASCII support by @hzx945627450-eng in #1293
- fix: clamp similarity scores to [0,1] to prevent negative values by @bobo-xxx in #988
- fix(searcher): guard against None metadata/doc in search result loops by @cantenesse in #1019
- fix: reject non-http(s) LLM endpoints + clear ruff bugbear/silent-except findings by @anthonyonazure in #1138
- fix(mcp): retry _get_collection once on transient failure (#1286) by @igorls in #1377
- docs: add 30-day expiry callout + ship 4 auto-save tools by @milla-jovovich in #1391
- fix(repair): add --mode from-sqlite to recover palaces with corrupt HNSW (#1308) by @potterdigital in #1310
- fix: harden Chroma repair preflight and rollback recovery by @mjc in #1285
- fix(miner): harden Windows mine against ONNX bad_alloc + silent partial exits (#1296) by @igorls in #1402
- fix: use configured collection in repair recovery paths by @mjc in #1312
- fix(migrate): verify write roundtrip before bailout by @fatkobra in #1359
- fix(storage): quarantine bloated HNSW link payloads by @fatkobra in #1339
- fix(repair): preflight poisoned max_seq_id before rebuild by @...