feat: optional shared/external MemPalace via MEMPALACE_REMOTE_URL
Lint workflows / actionlint (push) Successful in 21s
Lint workflows / actionlint (push) Successful in 21s
Wire the shared-palace option (implemented in mempalace-toolkit's mempalace.ts) into the container: - .env.example: document MEMPALACE_REMOTE_URL / MEMPALACE_REMOTE_TOKEN (env_file-only, per this repo's convention). - docker-compose.mempalace.yml: optional shared server (mempalace-mcp --transport http), loopback-bound by default. - docker-compose.yml: local-vs-external note on the palace-volume comment. - README + CHANGELOG (Unreleased).
This commit is contained in:
@@ -9,6 +9,19 @@ WORKSPACE_PATH=~/projects
|
|||||||
# Path to SSH keys on host
|
# Path to SSH keys on host
|
||||||
SSH_KEY_PATH=~/.ssh
|
SSH_KEY_PATH=~/.ssh
|
||||||
|
|
||||||
|
# ── MemPalace memory (local by default) ───────────────────────────
|
||||||
|
# By default the mempalace.ts extension spawns a LOCAL mempalace-mcp stdio
|
||||||
|
# server (palace at ~/.mempalace). Uncomment the devbox-palace volume in
|
||||||
|
# docker-compose.yml to persist it across container recreation.
|
||||||
|
#
|
||||||
|
# To instead share ONE MemPalace across containers/harnesses (pi + opencode
|
||||||
|
# + native), set the URL below. When set, the extension connects over HTTP
|
||||||
|
# and NO local mempalace-mcp is spawned; the devbox-palace volume is then
|
||||||
|
# irrelevant. MEMPALACE_REMOTE_TOKEN, if set, is sent as a bearer token.
|
||||||
|
# Serve it with: mempalace-mcp --transport http --host 0.0.0.0 --port 8765
|
||||||
|
# MEMPALACE_REMOTE_URL=http://mempalace.lan:8765/mcp
|
||||||
|
# MEMPALACE_REMOTE_TOKEN=
|
||||||
|
|
||||||
# ── LAN access from the container (host-OS-agnostic) ─────────────────
|
# ── LAN access from the container (host-OS-agnostic) ─────────────────
|
||||||
# On VM-backed hosts (macOS OrbStack / Docker Desktop) the container can't
|
# On VM-backed hosts (macOS OrbStack / Docker Desktop) the container can't
|
||||||
# reach the host's directly-attached LAN peers by default. The entrypoint
|
# reach the host's directly-attached LAN peers by default. The entrypoint
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- **Share one MemPalace across containers via `MEMPALACE_REMOTE_URL`.** The
|
||||||
|
`mempalace.ts` bridge (from `mempalace-toolkit`) can now connect to a shared
|
||||||
|
MemPalace over HTTP instead of spawning a per-container local server: set
|
||||||
|
`MEMPALACE_REMOTE_URL=http://<host>:8765/mcp` (optionally
|
||||||
|
`MEMPALACE_REMOTE_TOKEN`) in `.env` and no local `mempalace-mcp` is spawned.
|
||||||
|
A new `docker-compose.mempalace.yml` stands up such a shared server
|
||||||
|
(`mempalace-mcp --transport http`). Leaving the URL unset keeps the default
|
||||||
|
local-per-container palace. See `.env.example`. (The HTTP transport is
|
||||||
|
unauthenticated — keep it on a trusted network or behind a reverse proxy.)
|
||||||
|
|
||||||
- **Two non-modal terminal editors alongside `nvim`: `nano` and `micro`.**
|
- **Two non-modal terminal editors alongside `nvim`: `nano` and `micro`.**
|
||||||
The image previously shipped only `nvim` (with `EDITOR=nvim`), a modal
|
The image previously shipped only `nvim` (with `EDITOR=nvim`), a modal
|
||||||
vi-style editor. Not everyone is comfortable with vi keybindings, so both
|
vi-style editor. Not everyone is comfortable with vi keybindings, so both
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ on the host.
|
|||||||
- ChromaDB embedding model pre-warmed at build time (`all-MiniLM-L6-v2`)
|
- ChromaDB embedding model pre-warmed at build time (`all-MiniLM-L6-v2`)
|
||||||
|
|
||||||
The host-mounted palace at `~/.mempalace` is shared across the host and
|
The host-mounted palace at `~/.mempalace` is shared across the host and
|
||||||
this container so all your agents share one brain.
|
this container so all your agents share one brain. To instead share a palace
|
||||||
|
across *several* containers/harnesses, set `MEMPALACE_REMOTE_URL` to a shared
|
||||||
|
MemPalace HTTP endpoint (see `.env.example` and `docker-compose.mempalace.yml`);
|
||||||
|
the bridge then connects over HTTP and spawns no local server.
|
||||||
|
|
||||||
### Modern CLI tooling
|
### Modern CLI tooling
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# Shared MemPalace server (optional) — one palace for many clients.
|
||||||
|
#
|
||||||
|
# Runs `mempalace-mcp` over HTTP so several containers/harnesses (pi +
|
||||||
|
# opencode + native) can share ONE palace instead of each keeping its own.
|
||||||
|
# Point every client at it by setting, in that client's .env:
|
||||||
|
#
|
||||||
|
# MEMPALACE_REMOTE_URL=http://<reachable-host>:8765/mcp
|
||||||
|
#
|
||||||
|
# (see .env.example). When set, the client connects over HTTP and does NOT
|
||||||
|
# spawn its own local mempalace-mcp.
|
||||||
|
#
|
||||||
|
# Start: docker compose -f docker-compose.mempalace.yml up -d
|
||||||
|
# Stop: docker compose -f docker-compose.mempalace.yml down
|
||||||
|
# Logs: docker compose -f docker-compose.mempalace.yml logs -f
|
||||||
|
#
|
||||||
|
# Why reuse the devbox image? mempalace-mcp is already installed in it, and
|
||||||
|
# reusing it GUARANTEES the server's mempalace version matches the clients'
|
||||||
|
# (both are pinned by the same image build). Override with a slimmer image via
|
||||||
|
# MEMPALACE_SERVER_IMAGE if you prefer (it must provide `mempalace-mcp`).
|
||||||
|
#
|
||||||
|
# ⚠ SECURITY: mempalace-mcp's HTTP transport has NO authentication of its own.
|
||||||
|
# Do NOT expose port 8765 to an untrusted network. The default below binds to
|
||||||
|
# 127.0.0.1 (host loopback) only. To let sibling containers reach it, either
|
||||||
|
# attach them to the shared `mempalace-net` network (container-to-container, no
|
||||||
|
# host port needed — use http://mempalace-server:8765/mcp), or front it with a
|
||||||
|
# reverse proxy that enforces MEMPALACE_REMOTE_TOKEN as `Authorization: Bearer`.
|
||||||
|
|
||||||
|
name: mempalace-server
|
||||||
|
|
||||||
|
services:
|
||||||
|
mempalace:
|
||||||
|
image: ${MEMPALACE_SERVER_IMAGE:-joakimp/pi-devbox:latest}
|
||||||
|
container_name: mempalace-server
|
||||||
|
# Bypass the devbox entrypoint (dev-shell/LAN/config setup) and run the
|
||||||
|
# HTTP MCP server directly. HOME + explicit --palace pin the data path so
|
||||||
|
# it does not depend on the image's default user/HOME. Runs as root so it
|
||||||
|
# can initialise the fresh named volume; the volume is dedicated to this
|
||||||
|
# server (clients reach it over HTTP, never by mounting it).
|
||||||
|
entrypoint: []
|
||||||
|
user: "0:0"
|
||||||
|
environment:
|
||||||
|
- HOME=/data
|
||||||
|
command:
|
||||||
|
- mempalace-mcp
|
||||||
|
- --transport
|
||||||
|
- http
|
||||||
|
- --host
|
||||||
|
- "0.0.0.0"
|
||||||
|
- --port
|
||||||
|
- "8765"
|
||||||
|
- --palace
|
||||||
|
- /data/.mempalace
|
||||||
|
restart: unless-stopped
|
||||||
|
# Loopback-only by default (see SECURITY note). Use "8765:8765" to expose on
|
||||||
|
# all host interfaces, or drop `ports:` entirely and rely on mempalace-net.
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8765:8765"
|
||||||
|
volumes:
|
||||||
|
# The shared palace data — precious; back this up.
|
||||||
|
- mempalace-shared:/data/.mempalace
|
||||||
|
# Embedding-model cache (~79 MB, disposable) so search does not re-download.
|
||||||
|
- mempalace-shared-chroma:/data/.cache/chroma
|
||||||
|
networks:
|
||||||
|
- mempalace-net
|
||||||
|
healthcheck:
|
||||||
|
# A tools/list round-trip proves the server is answering MCP (python3 is
|
||||||
|
# always present — mempalace itself is a python tool in the image).
|
||||||
|
test:
|
||||||
|
- CMD
|
||||||
|
- python3
|
||||||
|
- -c
|
||||||
|
- "import urllib.request,json; d=json.dumps({'jsonrpc':'2.0','id':1,'method':'tools/list','params':{}}).encode(); r=urllib.request.Request('http://127.0.0.1:8765/mcp',data=d,headers={'Content-Type':'application/json','Accept':'application/json'}); urllib.request.urlopen(r,timeout=5).read()"
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mempalace-shared:
|
||||||
|
mempalace-shared-chroma:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
mempalace-net:
|
||||||
|
name: mempalace-net
|
||||||
+4
-1
@@ -76,7 +76,10 @@ services:
|
|||||||
# Persist uv data (Python installs, tool installs)
|
# Persist uv data (Python installs, tool installs)
|
||||||
- devbox-uv:/home/developer/.local/share/uv
|
- devbox-uv:/home/developer/.local/share/uv
|
||||||
|
|
||||||
# Optional: persist MemPalace data (conversation memory, knowledge graph)
|
# Optional: persist MemPalace data (conversation memory, knowledge graph).
|
||||||
|
# Applies to the LOCAL palace only (the default). In EXTERNAL mode
|
||||||
|
# (MEMPALACE_REMOTE_URL set in .env) the shared server owns the data, so
|
||||||
|
# this volume is irrelevant.
|
||||||
# - devbox-palace:/home/developer/.mempalace
|
# - devbox-palace:/home/developer/.mempalace
|
||||||
|
|
||||||
# Optional: persist ChromaDB embedding model cache (~79 MB)
|
# Optional: persist ChromaDB embedding model cache (~79 MB)
|
||||||
|
|||||||
Reference in New Issue
Block a user