Skip to content

Releases: MemPalace/mempalace

v3.9.0 — one hub for every agent

Choose a tag to compare

@igorls igorls released this 31 Aug 10:25
d5250c7

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 search reuses 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

Full Changelog: v3.8.0...v3.9.0

v3.8.0 — fast large palaces, lean MCP proxies, wakeable agents

Choose a tag to compare

@igorls igorls released this 23 Aug 21:11
87e6f38

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_drawers and tunnel reads now query Chroma's SQLite metadata directly, push filters into SQL, and hydrate only the requested previews. (#2314)
  • sqlite_exact common reads no longer walk the whole palace. On a live 167k-drawer / 166k-closet palace, mempalace_status fell from 6997 ms to 1045 ms and warm mempalace_search from 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, and wing / room / hall gain 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 watch provides 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 --apply no longer deletes drawers whose source file it could not reach. One Path.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 one sync --apply while 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 new unresolved bucket, 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_peers can report reachability and profiles from stdio as well as HTTP. (#2309)
  • Filesystem edge cases fail safely. sweep reports failed stats, init handles unreadable manifest paths, and split refuses 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

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

Choose a tag to compare

@igorls igorls released this 14 Aug 17:51
359c579

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.walk and glob list a FIFO as an ordinary filename and MemPalace decides what to read from the suffix, so a pipe called notes.md in a mined directory wedged mine in the kernel forever: opening a FIFO for reading waits for a writer that never arrives, and the S_ISREG refusal written on the next line could never run. mine --mode convos, sweep, init, compress and split blocked the same way through their own readers. The four affected opens now pass O_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 a SKIP: <name> (not a regular file) line, so the readers that use a plain open() 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 extract was 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 with chunk_total so file_already_mined can tell "N of N committed" from "crashed after batch 1"; (2) source_mtime comes from the same fstat as 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_set omits 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.sqlite3 on disk, both mcp_server._get_client and ChromaBackend._client drop chromadb's path-keyed SharedSystemClient cache 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 left mine_palace_*.lock naming a dead PID until a contender's liveness check reclaimed it. main() now installs handlers that exit through sys.exit, so the existing atexit release 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

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

Choose a tag to compare

@igorls igorls released this 11 Aug 12:35
7db7e0b

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/stream SSE). MCP tools include mempalace_event_append / list / wait / ack, artifact put/get, and patch submit; CLI mempalace logstream mirrors 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/embeddings endpoint (LM Studio, llama.cpp, vLLM, Ollama's OpenAI shim, or a self-hosted server) over stdlib urllib — 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_search and mempalace search accept since / before ([since, before) on filed_at), shared with list_drawers via mempalace.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 MemoryProvider files live turns through file_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 --mode paths 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_text line 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.float32 scalars that normalize_embeddings rejects. (#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_index holds 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_id on search; Claude Code subagents/ skipped by default (--include-subagents to 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 restore MEMPALACE_PALACE_PATH; systemd Restart=always with idle watchdog docs; valid docker-compose.yml environment 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 ...
Read more

v3.6.0

Choose a tag to compare

@igorls igorls released this 17 Jul 10:51
8ab251c

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 serve exposes 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-only both hides and refuses mutating tools. Docker Compose, systemd, and environment templates are included. (#1877, #1897, #1900)
  • Milvus storage backend. The new opt-in milvus backend 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_supersede closes 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_drawers also gains since / before bounds. (#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 hallways CLI command. (#1894, #1895)
  • Per-project mining exclusions through exclude_patterns in mempalace.yaml, without changing corrected --limit semantics. (#1213, #1953)
  • LaTeX project coverage for .tex and .bib prose 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 initialize immediately 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-sqlite rebuilds FTS5, vacuums, and requires a clean final PRAGMA 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; checkpoint and delete_by_source are 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 .gitignore handling 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_at migration 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.lock drift 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...
Read more

v3.5.0

Choose a tag to compare

@igorls igorls released this 23 Jun 01:02
2c08bb2

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 daemon serializes 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 http serves JSON-RPC at POST /mcp (with GET /healthz) for proxy/long-lived deployments. stdio remains the default; the HTTP path binds 127.0.0.1, pins Host and rejects non-loopback Origin (DNS-rebinding guard), and supports an optional MEMPALACE_MCP_HTTP_TOKEN bearer token. (#1801, #1806)
  • mempalace_checkpoint batch-save tool. Files multiple add_drawer calls plus an optional diary entry in a single MCP round-trip, verbatim, reusing the idempotent add/dedup path. (#1851)
  • mempalace_delete_by_source bulk-cleanup tool. Exact-match, dry-run-by-default deletion of every drawer and its closet/AAAK index entries for a source_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_file filter for mempalace_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 SessionEnd so the last exchanges are captured at session close. (#1814, #1820)

Performance

  • Overview/status and graph_stats answered 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) and pgvector (#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-windows retries 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

Full Changelog: v3.4.1...v3.5.0

v3.4.1

Choose a tag to compare

@igorls igorls released this 15 Jun 09:38
bc9c052

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 the mempalace-mcp server, five slash commands (/mempalace-help, /mempalace-init, /mempalace-mine, /mempalace-search, /mempalace-status), and a model-invocable skill — no manual ~/.cursor/mcp.json edit. 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 at hooks/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 on Stop, 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-mcp console-script shebang before falling back to python3, fixing silently-no-op mining under uv tool install / pipx layouts where the system python3 can't import mempalace.

Bug Fixes

  • embeddinggemma no 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 migrate and mempalace repair max-seq-id wrote 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 new max_backups setting (default 10; 0 keeps 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

Full Changelog: v3.4.0...v3.4.1

v3.4.0

Choose a tag to compare

@igorls igorls released this 06 Jun 08:58
be95467

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. See docs/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_id hash collisions.
  • Importing mcp_server no longer recreates ~/.mempalace (respects the privacy kill-switch).
  • diary_write accepts a content alias 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

Choose a tag to compare

@milla-jovovich milla-jovovich released this 06 Jun 07:27
db1fbe8

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. New mempalace mine <dir> --mode extract ingests PDFs, Word (.docx), PowerPoint (.pptx), Excel (.xlsx), RTF, and EPUB books in addition to the existing source-code/text path. Install with pip install mempalace[extract] — pulls striprtf for 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 carry extract_mode metadata 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-dateutil is 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_wing so 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_tunnel manually. Topic tunnels from the existing compute_topic_tunnels path 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 dedicated wing_api instead 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-300m ONNX (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. New EmbeddinggemmaONNX class in mempalace/embedding.py brings this to 0.88 average (validated lossless vs the Ollama gguf via direct ONNX-runtime test). Lazy-downloads onnx-community/embeddinggemma-300m-ONNX (~300 MB) on first use via huggingface_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 writes embedding_model: embeddinggemma to config.json so subsequent runs pick it up without re-prompting. Existing installs that never set the env var or ran onboarding stay on minilm (back-compat). MEMPALACE_EMBEDDING_MODEL=minilm|embeddinggemma overrides both. Switching models on an existing palace requires re-embedding — run mempalace repair rebuild-index after the change. (#1483)

  • Multilingual deps moved to core. huggingface_hub, tokenizers, and numpy are now required deps so the multilingual path works out of the box after pip 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_MODEL on an existing palace without running rebuild-index previously surfaced ChromaDB's bare Embedding function conflict: new: X vs persisted: Y ValueError — 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 run mempalace repair rebuild-index --palace <path>. (#1483)

  • hooks.auto_save toggle for silent-mode sessions. New config knob (and --silent CLI flag wiring through the save hook) lets users opt out of automatic diary saves on Stop / 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_SIZE and 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 honor CHUNK_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_tunnel corrupted 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/palace and /Users/me/.mempalace/Palace (case-folded on macOS) or a symlinked alias produced two separate cached KnowledgeGraph instances pointing at the same SQLite file, with stale-read risk. Cache now normalizes via realpath + normcase so 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, so mem-palace became mem. 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...

Read more

v3.3.5 — integrity, recovery, and cross-process correctness

Choose a tag to compare

@igorls igorls released this 10 May 23:32
d0163a7

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-sqlite recovers palaces stuck on apply_logs. When ChromaDB's HNSW segment writer wedges (the corruption class reported upstream and in #1308), --mode legacy and the inline repair both call Collection.count() as their first read — which is exactly the call that raises. The old failure mode was a repair printing Cannot recover — palace may need to be re-mined from source files even though the SQLite tables were fully intact. The new mode reads (id, document, metadata) directly from chroma.sqlite3 via 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_from used to be durably stored but unreachable (the temporal filter matched no as_of); add_triple() now rejects inverted intervals at write time. And date strings forwarded to SQLite are validated up front via sanitize_iso_temporal() (alias sanitize_iso_date()), which accepts YYYY-MM-DD and 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-atomic Path.write_text() — a power loss, OOM, or kill -9 between truncate and full-flush would silently wipe it (the registry's load() swallows JSONDecodeError). Save now writes to a sibling temp file, fsyncs, and os.replace()s into place. The previous registry stays intact on any crash before the rename returns. (#1215)

  • MCP tool_search rides 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 hitting Internal error: Error finding id for that entire window. tool_search now 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 with index_recovered: true so callers can observe when it fired. Partial fix for the broader #1315 cluster — tool_check_duplicate and 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 after shutil.rmtree no longer fails with SQLITE_READONLY_DBMOVED. And the MCP server's _kg is no longer a module-level singleton: multi-tenant hosts rotating MEMPALACE_PALACE_PATH between 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.txt and piped fact_checker invocations no longer mojibake Cyrillic / CJK drawer text at the process boundary. mcp_server, hooks_cli, and cli/fact_checker all reconfigure identically. (#1282)

  • miner.detect_room routing 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.tsx routed to an interviews room because "views" in "interviews" matched first. Now uses separator-bounded token matching (-, _, ., /). (#1004, closes #1002)

  • mempalace compress no longer crashes on palaces above ~32k drawers. Drawer fetch is now paginated, mirroring the #851 fix in miner.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 @...
Read more