TechEmpower's production fork of rboarescu/palace-daemon (transferred from jphein/palace-daemon in May 2026)
Fork of rboarescu/palace-daemon, tracking upstream/main through the 2026-04-27 sync (upstream is at v1.5.1; this fork is at v1.7.2-with-unreleased-fork-work — the /graph endpoint, /viz status dashboard, auto-repair-on-startup, and post-merge deployment tooling that 1.7.2 captured, plus the substantial 2026-05-11 → 2026-05-15 reliability + hybrid-retrieval push captured under [Unreleased] in the CHANGELOG). Running in production since 2026-04-24, currently fronting the techempower-org/mempalace 273k-drawer Postgres + pgvector + Apache AGE palace on familiar:8085. The bulk of the v1.5.0 daemon work (cold-start warmup, /repair, /silent-save, themed messages, --palace flag, MCP timeout) was contributed back to upstream as PR #4; rboarescu cherry-picked the contents into upstream main directly as ef6ac03 on 2026-04-25 and closed the PR.
2026-05-11 → 2026-05-17 fork-side push (unreleased, on main): hybrid-retrieval endpoints (POST /search/hybrid + POST /search/keyword — vector ∪ tsvector-BM25 ∪ AGE-graph candidates, hybrid-reranked), POST /cypher + POST /embed for direct AGE / pgvector access, the Stop/PreCompact hook detach fix (fork + setsid + dup2 all three FDs so claude's harness pipes can close), canonical-room boundary validation in /memory, and ops/scripts/deploy-palace-daemon.sh — a one-shot deployer that replaces the previous syncthing-based mirror path. New 2026-05-17: POST /search/age-fused endpoint — Phase 5 of the multi-project AGE-integration plan (see techempower-org/palace-daemon#25 and companion mempalace PR #101). Combines vector retrieval with AGE entity-overlap via RRF fusion — graph_only beats vector by +5pp R@5 on a 2026-05-17 n=200 git-derived probe spike; fusion adds another +4pp on top. Full day-by-day in CHANGELOG.
2026-05-25 milestone — AGE knowledge-graph backfill complete. The /backfill-age endpoint (commit b4016c6) finished its first full pass on the production palace. mempalace_kg is now populated with 89 Wings, 8 Rooms, 365,496 Drawers, and 263,982 Entities — 629,575 nodes total, joined by 5,945,419 edges (5.58M Drawer-[:MENTIONS]->Entity edges, 365k Room-[:CONTAINS]->Drawer, 3.1k Wing-[:SHARED_VIA]->Wing tunnel edges, 197 Wing-[:CONTAINS]->Room). 0 errors, ~61min wall clock, returncode 0. Graph-fused retrieval (/search/age-fused), entity-anchored /cypher queries, and the mempalace_walk_palace MCP tool now have real material to traverse — the +5pp R@5 graph-only lift from the 05-17 spike should reproduce against the full palace. See CHANGELOG for the next-step roadmap.
2026-05-28 milestone — canonical predicate vocabulary collapse. The graph's r.relation_type vocabulary went from ~64k freeform LLM-derived strings to 40 canonicals + ~195 retained code-token raws (#75 / #77 / #85). Migration applied to 1,761,790 RELATION edges, mapping 755,034 (42.9%) to a canonical and binning the rest as 'other' (originals preserved as raw_relation_type for reversibility). Set-based postgres UPDATE on the AGE backing table at ~63k edges/sec after per-cypher batches hit AdminShutdown at the 8th wave from MVCC dead-tuple bloat. GPU-accelerated embedding (onnxruntime-gpu on a 2080 Ti) gave ~65× speedup over CPU for the migration. The canonical-mapping modules now ship from mempalace (mempalace#290; palace-daemon #87 reduced the local files to thin re-export shims, then #90 retired the shims entirely). Stage-distinguished KG write-through logging (#78 / #83) — the startup log now reports MENTIONS=on/off and EXTRACTION_QUEUE=on/off separately, so operators can tell which stage is active. Until this landed, the graph leg of mempalace_search?candidate_strategy=hybrid was effectively a no-op — most edges' relation_type appeared once. With the collapsed vocabulary, hybrid candidates can traverse a meaningful semantic surface; the latency + scorer-weight tuning that this exposes is tracked in #80 and upstream-mirrored as mempalace#291.
What this fork adds that you won't get from upstream yet: a GET /viz status dashboard (self-contained HTML page that fetches /graph, /repair/status, and /health in parallel and renders five panels — status strip with repair pulse, D3 force-directed knowledge graph, Mermaid wing/room hierarchy, tunnels list, wings bar chart — D3 + Mermaid via CDN, no static-file deps); a GET /graph endpoint (single-shot structural snapshot for SME-style consumers, ~0.4s on the 151K-drawer palace via direct read-only sqlite reads of embedding_metadata and knowledge_graph.sqlite3 — vs. ~60-120s for the equivalent serial MCP composition under load); GET /list for query-free metadata browse by wing/room (wraps mempalace_list_drawers, the right path when /search would fall back to BM25 and ignore the wing filter); DELETE /memory/{id} + PATCH /memory/{id} REST CRUD over mempalace_delete_drawer / mempalace_update_drawer so curation UIs don't have to talk MCP just to fix a typo; lifespan auto-migrate of pre-3.3.4 Stop-hook checkpoints into mempalace_session_recovery on first restart post-upgrade (idempotent, ImportError-gated, env-overridable via PALACE_AUTO_MIGRATE_CHECKPOINTS=0); auto-repair-on-startup that detects degraded HNSW recall after restart and fires /repair {mode:rebuild} non-blocking in the background (workaround that bought time for the mempalace fork's 645ba20 integrity gate fix to land); the limit= parameter actually being honored (earlier versions silently capped at 5 due to a max_results→limit name mismatch the MCP tool's whitelist dropped); a scripts/deploy.sh that bundles git push → wait for sync → systemctl restart → /health poll → verify-routes smoke test into one command; scripts/verify-routes.sh as a curl-based smoke test for every public route; clients/palace-mode CLI for one-command local↔remote palace switching; clients/palace-mcp-dispatch.sh that picks daemon vs. in-process MCP based on PALACE_DAEMON_URL; and clients/mempal-fast.py — a stdlib-only Stop/PreCompact hook handler that POSTs to /silent-save without importing mempalace (so cold hook fires can't trigger ChromaDB's HNSW SIGSEGV class). Full list below.
v1.7.2 release notes · PR #4 — upstream contribution · Discussion #5 — Postgres backend · Discussion #6 — TS rewrite heads-up · docs/event-log-frame.md — daemon-as-view-coordinator architectural frame · docs/typescript-port-plan.md — TS rewrite planning artifact (no commitments, sections marked [OPEN]/[LEANING]/[DECIDED])
Per PR #4 issue comment, rboarescu welcomed post-1.5.0 work as small separate PRs at whatever cadence works.
| PR | Status | Description |
|---|---|---|
| #7 | OPEN, awaiting review | fix: honor limit= on /search and /context — two-line rename max_results → limit so the user-supplied value actually binds (the MCP tool's input_schema declares limit, so max_results was being silently dropped). |
| #8 | OPEN, awaiting review | feat: canonicalize Stop-hook topic at daemon boundary with warning log — _canonical_topic() rewrites legacy synonyms ("auto-save" → "checkpoint") on the /silent-save path and emits a warning so client-side drift is observable. Composes with upstream's 0060190 CHECKPOINT_TOPIC constant. |
| #9 | OPEN, awaiting review | chore(scripts): add verify-routes.sh smoke test — curl-based smoke test for every public read-only route. Universal, no fork-mempalace dependencies. |
| #10 | OPEN, awaiting review | fix(clients): resolve mempalace-mcp.py via readlink, not absolute path — bug fix: dispatcher in clients/palace-mcp-dispatch.sh as shipped in upstream main has a hardcoded /home/jp/Projects/... path (accidentally embedded during PR #4's extraction) and fails on every machine except mine. +6/-1 readlink -f sibling resolution. |
| #11 | OPEN, awaiting review | docs: event-log frame — palace-daemon as materialized-view coordinator — architectural reference doc (191 lines) articulating mempalace as Kleppmann-shaped (log + materialized views), the daemon as the view coordinator. Useful frame ahead of the multi-backend transition. |
| #12 | OPEN, awaiting review | fix(clients): remove embedded API key + URL defaults from palace-mode — clients/palace-mode shipped with a DEFAULT_URL pointing at JP's homelab and a real hex DEFAULT_KEY (rotated, but still in upstream's source). Reads both from env, fails fast in remote mode if either is unset. |
| #13 | OPEN, awaiting review | feat: GET /graph — single-shot structural snapshot for SME-style consumers — single endpoint returns wings + rooms-per-wing + tunnels + KG entities + triples + KG stats in ~0.4s on the canonical 151K palace; replaces the SME-style 60-120s serial MCP composition. Folds in the /graph.tunnels derive-from-graph_stats.top_tunnels fix so the response always agrees with /stats.graph.tunnel_rooms. Includes docs/graph-endpoint.md. +495/-0. |
| #14 | OPEN, awaiting review | chore(clients): add CHECKPOINT_TOPIC constant to mempal-fast.py — mirrors the constant already in clients/hook.py. Symmetry refactor; both client paths now source the canonical topic value from a per-file constant rather than mixing inline + constant. +8/-1. |
| #15 | OPEN, awaiting review | feat: GET /viz — self-contained status dashboard — single HTML page that fetches /graph, /repair/status, and /health and renders five panels (status strip, D3 KG, Mermaid wing/room tree, tunnels, wings bar). D3 + Mermaid via CDN, no new static-file plumbing. Stacks on #13 because the page consumes /graph. |
| #16 | OPEN, awaiting review | feat: GET /list — query-free metadata browse by wing/room — wraps mempalace_list_drawers so consumers can enumerate drawers in a wing without inventing an embeddable query (/search falls back to BM25 and ignores the wing filter when the query is non-embeddable). 34 lines of main.py. |
| #17 | OPEN, awaiting review | feat: DELETE /memory/{id} + PATCH /memory/{id} — REST CRUD over mempalace_delete_drawer / mempalace_update_drawer. Both tools have been in mempalace since 3.x; this just exposes them over HTTP for curation UIs. 29 lines of main.py. |
| #18 | OPEN, awaiting review | feat(lifespan): auto-migrate Stop-hook checkpoints to recovery collection on startup — calls mempalace.migrate.migrate_checkpoints_to_recovery() during lifespan startup so operators don't have to run the manual mempalace repair --mode reorganize after upgrading. ImportError-gated, env-overridable via PALACE_AUTO_MIGRATE_CHECKPOINTS=0. |
Note: PRs #8, #9, #10, #11, #12, #13 were each amended once on 2026-04-27 to address Copilot review feedback (force-pushed). Caught real bugs in several cases: PR #9's /health 503-hiding (curl -sS body grep masked HTTP status), PR #10's GNU-only readlink -f (failed on macOS), PR #13's rooms-from-wings-only logic bug (silent data loss on partial schema-drift) and _read_sem-bypass concurrency concern. Fixes also backported to fork main + deployed to production (152e428). PR #13 was rebased on 2026-04-30 to clear a CHANGELOG.md conflict with upstream's b4aee82 patch sync; PRs #15–#18 followed the same day after the rebase cleared the way.
- PR #4 (cherry-picked into upstream
mainasef6ac03, 2026-04-25, then closed): cold-start warmup,/repair,/silent-save, themed messages,--palaceflag, MCP timeout. The bulk of the v1.5.0 daemon work originated here.
The daemon depends on a tiny mempalace patch that's also in flight upstream:
- MemPalace/mempalace#1286 —
fix(mcp_server): log exception + retry once on _get_collection failure(filed 2026-04-30, againstdevelop). Currently applied locally aspatches/mcp_server_get_collection.patchviascripts/apply_patches.shon everypipx upgrade mempalace. Once #1286 merges, the patch retires entirely (delete the file, drop the apply step from the upgrade workflow). - MemPalace/mempalace#1142 —
docs: add RELEASING.md with mempalace-mcp pre-release check(filed 2026-04-23, againstdevelop). Process doc, no daemon dependency.
Everything the fork has ahead of upstream that hasn't been filed as a PR yet. Ranked from most PR-ready to least.
As of 2026-04-30, the queue is empty — every generalisable change ahead of upstream/main is now an open PR (#7 through #18). The remaining fork-only work is captured below under Needs generalization before PR.
All three previously-listed items (deploy.sh, palace-mode install, auto-repair-if-empty.sh) were generalized in #48 — they now read every host/path/auth value from env vars or an optional sourced config file, with portable defaults. Site-local values live in a gitignored scripts/deploy.conf (see scripts/deploy.conf.example).
The remaining fork-only items that are not yet PR-able are tracked as separate issues.
The fork's /graph endpoint replaces what an SME-style adapter would otherwise compose by serially calling list_wings + list_rooms × N + list_tunnels + kg_stats over MCP:
$ time curl -sS -H "X-Api-Key: $KEY" https://palace.jphe.in/graph | jq '{
wings: (.wings | length),
pairs: ([.rooms[] | .rooms | length] | add),
tunnels: (.tunnels | length),
kg: {
entities: (.kg_entities | length),
triples: (.kg_triples | length),
mentions: (.kg_mentions | length)
}
}'
{
"wings": 36,
"pairs": 165,
"tunnels": 9,
"kg": { "entities": 6, "triples": 1, "mentions": 5 }
}
real 0m0.876sDeploy is a single command that catches sync-lag footguns (Syncthing-mirrored deployment between dev and prod hosts):
$ scripts/deploy.sh
▸ 1/5 push to origin ✓ pushed 00ec6be → origin/main
▸ 2/5 wait for sync to familiar ✓ remote at 00ec6be
▸ 3/5 restart palace-daemon ✓ restart issued
▸ 4/5 wait for daemon health ✓ healthy on v1.7.0 (after 3s)
▸ 5/5 smoke-test routes ✓ all 12 routes verified
✦ deploy complete: 00ec6be on http://familiar:8085Local↔remote palace switching is one command:
$ palace-mode status
Mode: remote (http://familiar:8085)
$ palace-mode local
→ local mode
$ palace-mode remote http://familiar:8085
→ remote mode (PALACE_DAEMON_URL=http://familiar:8085)A Stop hook fires from any Claude Code session and routes through the daemon without ever loading mempalace locally:
[06:29:17] Daemon silent-save: queued=False count=14 (fast-path)
[06:29:17] Skipping auto-ingest: PALACE_DAEMON_URL set, daemon owns writes
The /viz dashboard is a single bookmark for live state — drawer count, repair pulse, KG, wing/room tree, tunnels:
https://palace.jphe.in/viz?key=$KEY&refresh=15
Auto-repair self-heals after a daemon restart that leaves HNSW empty (the false-positive quarantine cascade — pre-fix shape):
06:56:42 systemd: Starting palace-daemon...
06:56:45 Quarantined 3 stale HNSW segment(s) — ChromaDB will rebuild indexes
06:57:19 [auto-repair] daemon up after 15s
06:57:20 [auto-repair] DETECTED degraded HNSW recall: vector ranked 0
06:57:20 [auto-repair] kicking off /repair {mode:"rebuild"} in background — daemon stays available
After the mempalace-fork integrity-gate fix (645ba20) deployed alongside, the same restart now logs the post-fix shape and the auto-repair script exits no-op:
HNSW mtime gap 11165s on .../f360e835-... exceeds threshold but segment metadata file is intact — flush-lag, not corruption. Leaving in place.
HNSW mtime gap 11165s on .../02660268-... — Leaving in place.
HNSW mtime gap 11166s on .../4697d280-... — Leaving in place.
[auto-repair] HNSW recall looks healthy (no 'vector ranked 0' warning)
The upstream daemon focused on stability — semaphore-coordinated reads/writes, mine isolation, MCP-safe API key auth. JP's fork extended that into production deployment patterns:
-
Single-source-of-truth daemon for distributed Claude Code sessions. Multiple Claude Code instances (different projects, different terminals, different machines) all routing through one daemon prevents the kind of concurrent-writer SQLite corruption that took down the canonical palace on 2026-04-24. The fork's daemon-strict mode (in techempower-org/mempalace) plus this daemon's queue-and-drain plus
mempal-fast.py's no-import path together make that single-writer guarantee enforceable. -
Structural snapshots for evaluation frameworks. When SME (multipass-structural-memory-eval) needed a structural view of the palace for diagnostics, composing it serially over MCP timed out at 60-120s. The fork added
GET /graphso an evaluator can pull wings, rooms, tunnels, KG entities, and KG triples in one HTTP roundtrip — sub-second on a 151K-drawer palace. -
Operational ergonomics.
palace-modefor switching local/remote,deploy.shfor the one-command release,verify-routes.shfor post-restart smoke testing — these are quality-of-life pieces for a daemon that's actually used day-to-day rather than just installed.
The architectural argument for why those pieces survive backend swaps (chroma → pgvector, etc.) is in docs/event-log-frame.md.
-
Single-writer enforced by design. SQLite + Syncthing replication + multiple writers = corruption. The daemon is the only process that writes to the palace; clients route through it via HTTP/MCP. The fork's
mempal-fast.pyandpalace-mcp-dispatch.shmake that property hold even for hooks and MCP servers. -
Direct sqlite reads for structural data.
embedding_metadataandknowledge_graph.sqlite3are read-only via?mode=roURI for/graph. Bypasses the MCP read semaphore entirely, ~200× faster than the equivalent fan-out under load. Same pattern, different table, for the KG. -
Themed messages for save/repair lifecycle.
messages.pyreturns user-facing strings insystemMessageso a Claude Code Stop hook surfaces✦ N memories woven into the palacewithout the client knowing the internal save/queue state. -
Coordinated rebuild with queue-and-drain.
/repair mode=rebuildholds every read/write/mine semaphore slot during the destructive collection swap;/silent-savequeues to<palace>/palace-daemon-pending.jsonland replays automatically post-rebuild. No saves lost during a rebuild window. -
Deploy and verify are the same command.
deploy.shexits non-zero on sync lag, restart failure, or any verify-routes regression. The default cadence for shipping a daemon change is push + restart + verify; if any step fails the deploy aborts, leaving the previous version running.
- Python 3.12+
- mempalace ≥ 3.3.2 — the fork is recommended if you want daemon-strict hook mode (single-writer enforcement) and the warnings/sqlite-fallback search path that aren't yet on
MemPalace/mempalace develop. Stock mempalace works for everything else; the fork-onlymigrate_checkpoints_to_recoverylifespan call isImportError-gated and degrades cleanly. - For the local mempalace patch (
patches/mcp_server_get_collection.patch— log + retry on_get_collectionfailure, in flight upstream as #1286): re-apply withscripts/apply_patches.shafter eachpipx upgrade mempalaceuntil #1286 merges.
Uses uv for venv + dependency install — faster than pip and doesn't require the python3-venv apt package (which isn't installed by default on Ubuntu 24.04).
git clone https://github.com/techempower-org/palace-daemon.git
cd palace-daemon
uv venv venv
uv pip install --python venv/bin/python -r requirements.txtpip fallback (if uv unavailable)
python3 -m venv venv # requires apt install python3.12-venv on Ubuntu
source venv/bin/activate
pip install -r requirements.txtuv is preferred; the stdlib venv + pip path is legacy and noted only for hosts that don't have uv installed.
# Default: port 8085, palace at $PALACE_PATH or ~/.mempalace/palace
python main.py
# Custom palace path + auth
PALACE_API_KEY=$(openssl rand -hex 32) python main.py --palace /srv/mempalace-data/palacesudo cp palace-daemon.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now palace-daemonEdit the unit file to set User=, Group=, the ExecStart= venv path, PALACE_API_KEY, MEMPALACE_PALACE, and any custom args before installing.
System unit is the only supported configuration. Per CLAUDE.md "Service Management" rule: sudo systemctl [start|stop|restart] palace-daemon is the canonical control path.
Caution
Never install BOTH the system unit AND a ~/.config/systemd/user/palace-daemon.service. Both run with ExecStartPre=/usr/bin/fuser -k 8085/tcp and will kill each other's listener in a cascade — the second instance's startup hook kills the first's listener, then the first restarts and kills the second. Restart counters in the hundreds within minutes is the symptom. If you have both, delete the user unit at ~/.config/systemd/user/palace-daemon.service (along with any .bak siblings) and run systemctl --user daemon-reload.
Caution
Don't expose port 8085 without setting PALACE_API_KEY. The /mine endpoint accepts arbitrary filesystem paths.
Use palace-mode install to wire the mempalace plugin cache to talk to this daemon (after pointing PALACE_DAEMON_URL at it):
export PALACE_DAEMON_URL=http://your-host:8085
export PALACE_API_KEY=...
./clients/palace-mode install
./clients/palace-mode verifyThis installs mempal-fast.py as the Stop/PreCompact hook handler and palace-mcp-dispatch.sh as the MCP server command in the plugin cache. Idempotent — safe to re-run after plugin updates.
| Route | Method | Purpose |
|---|---|---|
/health |
GET | Liveness + version + crash-loop state; returns 503 when degraded or crash_loop |
/search |
GET | Semantic search over mempalace_drawers; limit=N. (Stop-hook checkpoints live in mempalace_session_recovery — read via the mempalace_session_recovery_read MCP tool.) |
/search/hybrid |
POST | Hybrid search — vector + BM25 + graph in one ranked set (candidate_strategy="hybrid") |
/search/keyword |
POST | BM25 keyword search over mempalace_drawers.doc_tsv with optional wing/room filters |
/search/age-fused |
POST | Vector + AGE graph fusion search with RRF merging |
/context |
GET | Same as /search, formatted for LLM prompts |
/list |
GET | Query-free metadata browse — wraps mempalace_list_drawers. wing=…&room=…&limit=N&offset=N, all optional |
/stats |
GET | Aggregate KG + graph + status counts |
/graph |
GET | Single-shot structural snapshot (wings, rooms, tunnels, KG) — see docs/graph-endpoint.md |
/viz |
GET | Self-contained HTML status dashboard (D3 + Mermaid). Optional ?refresh=N, ?key=… |
/cypher |
POST | Run a Cypher query against the AGE knowledge-graph; returns aliased rows (no SQL wrapper needed) |
/embed |
POST | Embed a list of texts via the daemon's configured embedding function; returns vectors + dim + model |
/repair |
POST | Coordinate repair (mode=light|scan|prune|rebuild) |
/repair/status |
GET | Current repair state + pending-writes queue depth |
/silent-save |
POST | Stop-hook save path with queue-and-drain during rebuild |
/memory |
POST | Store a drawer with taxonomy enforcement (wing normalization + canonical room validation) |
/memory/{id} |
DELETE | Drop a drawer — wraps mempalace_delete_drawer |
/memory/{id} |
PATCH | Update drawer content / wing / room (all optional in body) — wraps mempalace_update_drawer |
/admin/refresh-rooms |
POST | Clear + eagerly rebuild the canonical rooms cache (after mempalace rooms add); returns {refreshed, rooms, count} |
/mine |
POST | Bulk import a directory (validated absolute path only) |
/watch |
GET | List directories the file-watcher is currently monitoring (configured via PALACE_WATCH_DIRS) |
/flush |
POST | Force checkpoint of pending writes |
/reload |
POST | Invalidate cached client + collection |
/backup |
POST | SQLite snapshot to a sibling file |
/mcp |
POST | MCP-protocol passthrough |
All endpoints honor X-Api-Key when PALACE_API_KEY is set.
# Smoke-test the running daemon
PALACE_DAEMON_URL=http://localhost:8085 PALACE_API_KEY=... scripts/verify-routes.sh
# One-command deploy (push + sync-wait + restart + verify)
scripts/deploy.sh
# Switch local Claude Code sessions between modes
palace-mode {status,local,remote [URL],install,verify}
# Live integrity monitor — ANSI dashboard with alerts
python monitor.py --url http://familiar:8085 --interval 5| Script | Description |
|---|---|
scripts/deploy.sh |
One-command git push → wait for sync → systemctl restart → /health poll → verify-routes deploy. |
scripts/verify-routes.sh |
curl-based smoke test for every public route. |
clients/palace-mode |
Local↔remote palace switching (status, local, remote [URL], install, verify). |
clients/mempalace-mcp.py |
stdio MCP proxy: bridges the MCP client to the daemon over HTTP. Honors mcp_mode (see below). |
clients/palace-mcp-dispatch.sh |
Picks daemon vs. in-process MCP based on PALACE_DAEMON_URL. |
clients/mempal-fast.py |
Stdlib-only Stop/PreCompact hook handler — POSTs to /silent-save without importing mempalace. |
monitor.py |
Standalone live integrity monitor. Polls /health, /stats, /repair/status and prints an ANSI dashboard with alerts for unreachable, degraded, drawer-count drops, and active repairs. Usage: python monitor.py --url http://familiar:8085 --interval 5 |
The MCP tool surface costs ~9k tokens of schemas on every session start. The two things you usually want to keep — auto-save hooks and skills — are independent of the MCP server (hooks POST to the daemon directly; skills are markdown loaded by the harness). So the tool surface can be made opt-in per machine without losing either.
The stdio proxy (clients/mempalace-mcp.py) reads mcp_mode from
~/.mempalace/config.json once at startup, with the env var PALACE_MCP_MODE
as an ephemeral override (env beats file):
mcp_mode |
tools/list |
tools/call |
initialize / ping / notifications/* / resources/list / prompts/list |
|---|---|---|---|
all (default, or unset/unknown) |
forwarded — all tools present | forwarded | forwarded (unchanged) |
cli-only |
returns {"tools": []} without forwarding |
rejected with JSON-RPC -32601 |
forwarded — server still shows ✓ Connected (with 0 tools) |
# Ephemeral override for one session
PALACE_MCP_MODE=cli-only claudeFail-open: a missing file, missing key, unreadable/garbled config, or an
unknown value all resolve to all — a typo never silently kills the tool
surface. Only an explicit cli-only suppresses tools.
Reload requirement: MCP clients read tools/list once per session, so the
visible tool set (and the context savings) changes on the next /mcp reconnect
or harness restart, not mid-session. Re-enable by flipping mcp_mode back to
all (or removing the key) and reconnecting — no claude mcp add dance, no
manifest editing.
In cli-only mode drive the palace from the CLI: mempalace search/list/graph/cypher/wake-up/status/….
- rboarescu/palace-daemon — upstream
- MemPalace/mempalace — the underlying memory system this daemon fronts
- techempower-org/mempalace — the production fork of mempalace this daemon is paired with
- multipass-structural-memory-eval — the SME framework whose palace-daemon adapter consumes
/graph - Apache AGE — graph extension for postgres, candidate KG view technology if mempalace's KG ever justifies it (currently doesn't)
- pgvector — vector extension for postgres, candidate semantic-search view technology under upstream MemPalace #665
- D3.js + Mermaid —
/vizdashboard rendering, both via CDN, no bundler / no static-asset deps - Upstream PRs that informed
/viz: #1022 (D3 KG viz, sangeethkc), #393 (Mermaid in docs, jravas), #431 (CLI stats, MiloszPodsiadly), #256 (sync_status MCP, rusel95), #601 (brief overview, mvanhorn) — synthesized, not cherry-picked - Cross-repo PRs that retire local code paths if/when they merge: MemPalace/mempalace#1286 — log + retry on
_get_collectionfailure (would retirepatches/mcp_server_get_collection.patch)
MIT — same as upstream.