From b9c08c3dbbc150e3026a1d7765dd45bb025e6263 Mon Sep 17 00:00:00 2001 From: Joakim Persson Date: Mon, 27 Apr 2026 19:25:38 +0200 Subject: [PATCH] Add MemPalace local-first AI memory system to base image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install mempalace via pip in the Dockerfile. Provides 29 MCP tools for semantic search over conversation history, knowledge graph queries, agent diaries, and wing/room/drawer management. Everything runs locally — no API keys, no data egress. Integration: - Dockerfile: pip install mempalace (with --break-system-packages for Debian trixie PEP 668 compliance) - entrypoint-user.sh: auto-initializes palace for /workspace on first run (idempotent, skips if palace exists) - entrypoint.sh: adds ~/.mempalace to the volume ownership-fix loop - docker-compose.yml + shared: optional devbox-palace named volume at ~/.mempalace (commented out by default — user opts in) Users configure MCP integration by adding a mempalace server entry to their opencode.json. No wrapper plugin needed — the upstream Python MCP server is used directly. Docs updated: README.md (new MemPalace section with setup, MCP config, usage examples, storage details), DOCKER_HUB.md (data storage table + tools list), CHANGELOG.md (unreleased entry). --- CHANGELOG.md | 4 +++ DOCKER_HUB.md | 3 ++- Dockerfile | 7 +++++ README.md | 55 +++++++++++++++++++++++++++++++++++++++ docker-compose.shared.yml | 4 +++ docker-compose.yml | 7 ++++- entrypoint-user.sh | 11 ++++++++ entrypoint.sh | 1 + 8 files changed, 90 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 709ab8e..babe86b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a --- +## Unreleased + +- **Feature:** Add MemPalace local-first AI memory system to base image. Provides 29 MCP tools for semantic search over conversation history, knowledge graph queries, and agent diaries. Palace data persists via optional `devbox-palace` named volume. No API keys required. + ## v1.14.28 — 2026-04-26 Bump opencode to 1.14.28. diff --git a/DOCKER_HUB.md b/DOCKER_HUB.md index 90bc6f3..6041b12 100644 --- a/DOCKER_HUB.md +++ b/DOCKER_HUB.md @@ -230,6 +230,7 @@ Understanding what survives container restarts and what doesn't: | `/home/developer/.cache/bash` | Named volume `devbox-shell-history` | ✅ Yes — Docker volume | Bash history (`$HISTFILE`) — survives container recreate | | `/home/developer/.local/share/zoxide` | Named volume `devbox-zoxide` | ✅ Yes — Docker volume | Zoxide directory history (`z ` jump targets) | | `/home/developer/.local/share/nvim` | Named volume `devbox-nvim-data` | ✅ Yes — Docker volume | Neovim plugins, Mason LSP installs, Lazy plugin cache | +| `/home/developer/.mempalace` | Named volume `devbox-palace` (if configured) | ✅ Yes — Docker volume | MemPalace conversation memory, knowledge graph, embeddings | | `/home/developer/.local/share/uv` | Named volume (if configured) | ✅ Yes — Docker volume | Python installs, uv tool installs | | `/home/developer/.rustup` | Named volume (if configured) | ✅ Yes — Docker volume | Rust toolchains | | `/home/developer/.cargo` | Named volume (if configured) | ✅ Yes — Docker volume | Cargo binaries, registry cache | @@ -488,7 +489,7 @@ To override with your host's own files, uncomment the matching bind-mount lines - **opencode** — AI coding assistant - **Node.js 22** — for npx-based MCP servers - **AWS CLI v2** — SSO and Bedrock authentication -- **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync +- **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, mempalace, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync - **Non-root user** — runs as `developer` with UID auto-matched to workspace owner (sudo available) ### OMOS image (`latest-omos`) diff --git a/Dockerfile b/Dockerfile index a296580..2e62742 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,6 +47,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && ln -s /usr/bin/fdfind /usr/local/bin/fd \ && rm -rf /var/lib/apt/lists/* +# ── MemPalace — local-first AI memory system ───────────────────────── +# Provides semantic search over conversation history via 29 MCP tools. +# Palace data persists via the devbox-palace named volume. +# The embedding model (~300 MB) is downloaded on first use and cached +# in the palace directory. +RUN pip install --no-cache-dir --break-system-packages mempalace + # ── Go-compiled tools (install from GitHub to avoid CVEs in Debian's old Go builds) # gosu — privilege de-escalation (built with Go 1.24.6) diff --git a/README.md b/README.md index 17b4465..9febd99 100644 --- a/README.md +++ b/README.md @@ -444,6 +444,61 @@ The `--use-device-code` flag outputs a URL and short code instead of trying to o SSO sessions typically last 8–12 hours before requiring re-authentication. Since `~/.aws` is mounted from the host, tokens persist across container restarts. +## MemPalace — persistent AI memory + +The image includes [MemPalace](https://github.com/MemPalace/mempalace), a local-first AI memory system that stores conversation history verbatim and retrieves it via semantic search. Nothing leaves your machine. + +### Enabling persistence + +Uncomment the palace volume in `docker-compose.yml`: + +```yaml +- devbox-palace:/home/developer/.mempalace +``` + +Without the volume, palace data lives in the container's writable layer and is lost on `--force-recreate`. + +### MCP integration with opencode + +Add mempalace as an MCP server in your `opencode.json` (inside `~/.config/opencode/`): + +```json +{ + "mcp": { + "mempalace": { + "type": "local", + "command": ["python3", "-m", "mempalace.mcp_server"] + } + } +} +``` + +This gives opencode access to 29 MCP tools for searching memory, querying the knowledge graph, managing wings/rooms/drawers, and agent diaries. + +### Basic usage + +```bash +# Mine project files into the palace +mempalace mine /workspace + +# Mine conversation transcripts +mempalace mine ~/.local/share/opencode/ --mode convos + +# Search memory +mempalace search "why did we switch to eno1" + +# Load context for a new session +mempalace wake-up +``` + +Each workspace gets its own isolated "wing" — memories never leak between projects. + +### Storage + +- **Palace data** (ChromaDB vectors, SQLite knowledge graph, drawers): `~/.mempalace/` — persists via the `devbox-palace` named volume +- **Embedding model** (~300 MB): downloaded on first use, cached inside the palace directory +- **No API keys required** for core functionality (local embeddings via ONNX) + ## Shell defaults The image ships a baked `.bash_aliases` and `.inputrc` with quality-of-life defaults. On first container start they are copied from `/etc/skel-devbox/` into `/home/developer/` **only if the target file does not already exist** — so host bind-mounts and any version you've customized inside the container are never overwritten on upgrade. diff --git a/docker-compose.shared.yml b/docker-compose.shared.yml index f5803c7..c76d3e9 100644 --- a/docker-compose.shared.yml +++ b/docker-compose.shared.yml @@ -61,6 +61,9 @@ services: # Persist uv data (Python installs) - devbox-uv:/home/developer/.local/share/uv + # Optional: persist MemPalace data (conversation memory, knowledge graph) + # - devbox-palace:/home/developer/.mempalace + # Optional: AWS credentials (per-user if available) # - ${HOME}/${SIGNUM}/.aws:/home/developer/.aws @@ -70,3 +73,4 @@ volumes: devbox-zoxide: devbox-nvim-data: devbox-uv: + # devbox-palace: diff --git a/docker-compose.yml b/docker-compose.yml index 44bcdfb..f4c7d1c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -75,7 +75,7 @@ services: # in the container, mount the parent directory instead — see the # "Shell defaults" section in README.md. # - ~/.bash_aliases:/home/developer/.bash_aliases:ro - # - ~/.inputrc:/home/developer/.inputrc:ro + # - ~/.inputrc:/home/developer/.inputrc:ro # Optional: persist uv data (Python installs, tool installs) # Without this, 'uv python install' must be re-run after container removal. @@ -92,6 +92,10 @@ services: # Persist neovim plugin/Mason data (avoids re-downloading on every recreate) - devbox-nvim-data:/home/developer/.local/share/nvim + # Optional: persist MemPalace data (conversation memory, knowledge graph, + # embeddings). Without this, palace data is lost on container recreation. + # - devbox-palace:/home/developer/.mempalace + # Optional: AWS credentials/SSO config (not read-only — SSO writes token cache) # - ~/.aws:/home/developer/.aws @@ -102,6 +106,7 @@ volumes: devbox-zoxide: devbox-nvim-data: devbox-uv: + # devbox-palace: # devbox-rustup: # devbox-cargo: # devbox-vscode: diff --git a/entrypoint-user.sh b/entrypoint-user.sh index 359368e..f685974 100644 --- a/entrypoint-user.sh +++ b/entrypoint-user.sh @@ -15,6 +15,17 @@ if [ -d "$SKEL_DIR" ]; then done fi +# ── MemPalace: initialize palace for the workspace if mempalace is installed +# Creates the palace directory structure on first run. Idempotent — skips +# if palace already exists. Uses the workspace path to derive the wing name. +if command -v mempalace &>/dev/null && [ -d /workspace ]; then + PALACE_DIR="${HOME}/.mempalace" + if [ ! -d "$PALACE_DIR/palace" ]; then + echo "Initializing MemPalace for workspace..." + mempalace init /workspace 2>/dev/null || true + fi +fi + # ── Git config defaults ────────────────────────────────────────────── if [ -n "${GIT_USER_NAME:-}" ] && ! git config --global user.name &>/dev/null; then git config --global user.name "$GIT_USER_NAME" diff --git a/entrypoint.sh b/entrypoint.sh index fa4ae7f..59c7702 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -79,6 +79,7 @@ for dir in \ /home/"$USER_NAME"/.local/share/uv \ /home/"$USER_NAME"/.local/share/zoxide \ /home/"$USER_NAME"/.local/share/nvim \ + /home/"$USER_NAME"/.mempalace \ /home/"$USER_NAME"/.cache/bash \ /home/"$USER_NAME"/.rustup \ /home/"$USER_NAME"/.cargo \