Three coupled pieces of work, all of which ride on the base rebuild that the
mempalace bump forces anyway.
DRIFT ADOPTED
- pi 0.84.2 -> 0.84.3. Its release notes carry a "Breaking Changes" line
(GoogleThinkingLevel -> GoogleApiThinkingLevel). Audited before adopting:
zero references across all four vendored companions (pi-fork,
pi-observational-memory, pi-atelier, pi-studio), so it is inert for us. The
reason to adopt is two skill-discovery fixes that land directly on v1.8.5's
vendored-skill work: nested Markdown skills inside grouping directories were
not discovered, and root README.md/AGENTS.md in skill dirs were reported as
broken skills.
- mempalace core 3.7.1 -> 3.8.0. Additive/reliability only. Its sync fix
(#2320/#2322) stops sync --apply deleting drawers whose source_file was
unreachable *at that moment* -- which does NOT relax the standing landmine
against sync on the shared palace, because that landmine is about paths
permanently absent from whichever host runs the sync. Different failure
shape; the caution stands.
DOCS -- three defects, one of them public
- DOCKER_HUB.md advertised "neovim (LazyVim defaults)". Nothing in the image
installs LazyVim; the only nvim config is a 19-line sysinit.vim. CI PATCHes
this file into the Docker Hub description on every release, so this was a
false claim published to the world. Removed.
- agent-browser + Playwright + Chromium is the single largest addition in the
image (~625 MB) and had zero mentions in README, DOCKER_HUB or THIRD_PARTY --
it was documented only to agents, in the AGENTS.md managed block. Now
documented to humans, including the Chromium licence dimension.
- typst and socat appeared in README prose but not in the "What's inside"
inventory. Added.
OBSERVABILITY -- the three gaps v1.8.5 listed as still open
- build-manifest.json now records mempalace core, read from the live binary
(ground truth, not the build ARG). Placed as a sibling of pi_version rather
than inside components{}, because pi-devbox-version renders that map through
[0:12] and would truncate a version string.
- smoke asserts the pi-observational-memory clone actually CONTAINS the ce9fc98
auth fix, pinned to src/runtime.ts. Deliberately not a repo-wide grep: two of
the three markers also live under tests/, so the repo-wide form stays green
with the fix site reverted. That is the third false-green of this exact family
in this repo (canary phrase in both snapshots; reconciler fixture using a
non-owned name; now this) -- pin containment checks to the fix site.
- smoke asserts the feeder's pi@<device> agent default behaviourally. The
earlier audit concluded this needed a --print-config added upstream; it does
not. AGENT is assigned before arg parsing, so `bash -x mempalace-pi-session
--help` observes the real resolution with no toolkit change. Two-sided:
device set => pi@<device>, unset => must not be pi@*.
- pi-devbox-version now prints a palace: line with the same live-vs-baked drift
detection pi already had. This matters more than it looks: mempalace is the
one component that is both client (here) and server (synlig), so skew between
them is a real failure mode. Degrades quietly on pre-v1.8.6 images.
Deferred deliberately: a native arm64 act_runner on tor-ms22 (the current
runner is on synlig, x86_64, so every arm64 layer ships QEMU-emulated).
Analysis and caveats filed to the palace rather than actioned here.
11 KiB
pi-devbox
A self-contained Docker container for the pi coding-agent — pi + companion repos + MemPalace + a curated set of dev tooling, ready to run.
Current
:latestships pi{{PI_VERSION}}(resolved at build time; see Versioning).
Image variants
| Tag | Architectures | Size (compressed) | What you get |
|---|---|---|---|
joakimp/pi-devbox:latest |
amd64, arm64 | ~1.1 GB | Self-contained: base + pi {{PI_VERSION}} + companions |
joakimp/pi-devbox:vX.Y.Z |
amd64, arm64 | same | Pinned semver release |
joakimp/pi-devbox:latest-studio |
amd64, arm64 | ~1.15 GB | latest + pi-studio: browser prompt editor, KaTeX/Mermaid preview, tmux-backed literate REPLs |
joakimp/pi-devbox:vX.Y.Z-studio |
amd64, arm64 | same | Pinned semver studio release |
joakimp/pi-devbox:base-latest |
amd64, arm64 | ~1.0 GB | Base layer alias (internal building block; pull :latest instead) |
joakimp/pi-devbox:base-<hash> |
amd64, arm64 | ~1.0 GB | Content-addressed base; immutable. Stable parent for variant rebuilds. |
pi-studio (
-studiotags): launch with/studio --no-browser --port 8765inside a pi session. The server binds127.0.0.1inside the container, so reach it via host networking or a loopback bridge (andssh -Lfor a remote host; mosh needs a parallelssh -L). Full recipe: README → Using pi-studio.
Quick start
One-shot, no persistence:
docker run -it --rm \
-v "$PWD":/workspace \
-v "$HOME/.ssh":/home/developer/.ssh:ro \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
joakimp/pi-devbox:latest pi
For a fully-configured environment with persistent settings, MemPalace memory, neovim plugins, and shell history surviving container recreation, use docker-compose. You don't need to clone the repo — just grab two template files:
mkdir -p ~/pi-devbox && cd ~/pi-devbox
curl -O https://gitea.jordbo.se/joakimp/pi-devbox/raw/branch/main/docker-compose.yml
curl -fsSL https://gitea.jordbo.se/joakimp/pi-devbox/raw/branch/main/.env.example -o .env
# Edit .env — set WORKSPACE_PATH, an LLM API key (ANTHROPIC_API_KEY,
# OPENAI_API_KEY, GEMINI_API_KEY, or AWS_*), and your git identity.
docker compose run --rm devbox pi
Full setup guide — authentication for each provider (Anthropic, OpenAI, Gemini, AWS Bedrock SSO + static), persistence model, configuration reference, build args, troubleshooting: https://gitea.jordbo.se/joakimp/pi-devbox#readme
What's inside
pi and companions
- pi
{{PI_VERSION}}(@earendil-works/pi-coding-agent) — installed at/usr/bin/pi, pinned to an audited version (not npmlatest) - pi-atelier — TUI sidebar (ordered panels, split-pane, themes), vendored at
/opt/pi-atelierand pinned to an audited tag; the exact tag is in the image labels (se.jordbo.pi-devbox.pi-atelier-version) and/etc/pi-devbox/build-manifest.json - pi-toolkit — keybindings (mosh/tmux-friendly Shift+Enter, Ctrl+J, Alt+J newline bindings), AWS env loader, settings template
- pi-extensions — 7 user-facing extensions:
ext-toggle,mcp-loader,todo,ssh-controlmaster,notify,git-checkpoint,confirm-destructive fork(pi-fork) andrecall(pi-observational-memory) tools- mempalace bridge — MCP extension auto-symlinked so pi reads/writes the host-mounted palace
- image-baked agent skills — skills under
/usr/local/share/pi-devbox/skills/(e.g.pi-devbox-environment, which teaches agents the container's persistence/networking/DNS/tmux/REPL specifics) are symlinked into~/.agents/skills/on start, available with or without a mounted skillset repo
The entrypoint deploys/registers all of these on first container start. Re-running is idempotent and preserves user edits.
MemPalace (persistent agent memory)
- MemPalace + MCP server — semantic search over conversation history, knowledge graph, diary; queryable via 29
mempalace_*tools inside pi - ChromaDB ONNX embedding model pre-warmed at build time (
all-MiniLM-L6-v2) - Bind-mount your host's
~/.mempalaceand the host-pi and container-pi share one brain
Document and image tooling
- pandoc — universal Markdown↔HTML/Org/RST/etc. conversion. Useful well beyond pi: agent-driven doc exports, format conversion, etc.
- Typst — markup-based typesetting, used as pandoc's
--pdf-engine - graphviz (
dot) — diagram rendering pipelines - imagemagick (
magick) — image conversion / resizing
Browser automation
- agent-browser — CLI for driving a real browser (open pages, click/fill/
eval, snapshot the DOM, screenshots) so agents can verify front-end work instead of guessing - Playwright + a headless Chromium are pre-installed and pinned together;
AGENT_BROWSER_EXECUTABLE_PATHis preset to the baked browser, soagent-browser open <url>works out of the box with no setup - socat — TCP bridge used to expose the pi-studio server outside the container's loopback
Modern CLI tooling
- Editor: neovim (system-wide
termguicolorsdefault; bring your own config/plugins), tmux (configured for 0-indexed sessions) - Search/nav: ripgrep, fd, fzf, zoxide
- Display: bat, eza, htop, tree
- Data: jq, yq
- Help: tldr (tealdeer — Rust port; run
tldr --updateonce to populate cache) - Git: git-lfs, git-crypt, gitleaks (for pre-commit secret scanning)
- Build: gcc, g++, make, patch
- Misc: gosu, age, rsync, less
Language toolchains
- Python: system Python 3 + uv (preferred) for fast Python package management. Run any Python REPL/notebook stack on demand without bloating the image:
uv run --with ipython ipython uv run --with jupyterlab jupyter lab --no-browser --port 8888 uv run --with marimo marimo edit - Node.js v22 + npm (used by pi itself)
- Rust —
rustup-initis on PATH; install toolchains on demand - Go — opt-in via
--build-arg INSTALL_GO=trueif rebuilding from source
Cloud + secrets
- AWS CLI v2 — for SSO + Bedrock auth (pi's preferred LLM provider for the maintainer's setup)
- Gitea MCP server — for Gitea API access from inside pi
- age, git-crypt — encryption tooling
SSH and networking
- OpenSSH client with ControlMaster auto preconfigured on a writable socket path (
/tmp/sshcm/). Mitigates ssh banner-exchange failures behind CGNAT-restricted residential ISPs (~4-flow caps). A read-only~/.sshcarrying a per-hostControlPath(common CGNAT configs) is handled too — redirected to a writable socket dir for bothpi --sshanddssh/dscp. - A LAN-access helper that auto-configures ssh jump-via-host on VM-backed hosts (OrbStack / Docker Desktop on macOS) so the container can reach the host's directly-attached LAN peers (
dssh <peer>alias;DEVBOX_LAN_ACCESS/HOST_SSH_USER).
Versioning
From v1.0.0 onward, pi-devbox uses semver:
- Major — architectural changes. v1.0.0 is the first decoupled release, where pi-devbox got its own self-contained build chain (previously it was a thin re-brand of opencode-devbox's
pi-onlyvariant). - Minor — new image variants, significant base additions.
- Patch — pi version bumps, smaller fixes.
The pi binary version inside any given release is shown in this description (currently {{PI_VERSION}} for :latest) and asserted by smoke tests to match what's documented — version drift is caught at CI time, not on user pull.
Pre-v1.0.0 history. Tags v0.74.0…v0.79.0 followed the pi npm version directly (
v{pi_version}[letter]). Those images remain on Hub but are deprecated in favor of:latest/:v1.X.Y. The legacy:base-pi-only*tags were CI artifacts of the old opencode-devbox-based build pipeline; they will be removed in a future opencode-devbox v2.0.0.
Build pipeline
pi-devbox is built in two phases:
- Base (
Dockerfile.base) →base-<hash>tag, content-addressed overDockerfile.base+rootfs/+entrypoint*.sh. Rebuilt only when those change. - Variant (
Dockerfile.variant) →:latestand:vX.Y.Z. FROMs the base, adds the pi install + companions.
base-latest is an alias of the most recent base.
Persistent state
User edits and pi-installed packages survive container recreation when you mount these named volumes. Use the included docker-compose.yml and they're set up automatically.
| Volume | Mount point | What it holds |
|---|---|---|
devbox-pi-config |
/home/developer/.pi/ |
pi settings, extension toggles, sessions, user-installed pi packages (npm install -g, pi install npm:…) |
devbox-shell-history |
/home/developer/.cache/bash |
bash history |
devbox-zoxide |
/home/developer/.local/share/zoxide |
zoxide directory jump database |
devbox-nvim-data |
/home/developer/.local/share/nvim |
neovim plugin & Mason package state |
devbox-uv |
/home/developer/.local/share/uv |
uv Python installs and tool cache |
devbox-ssh-local |
/home/developer/.ssh-local |
LAN-jump key (one-time host authorization survives recreate) |
Optional volumes for MemPalace (commented out by default — uncomment in docker-compose.yml to persist conversation memory across restarts):
| Volume | Mount point | What it holds |
|---|---|---|
devbox-palace |
/home/developer/.mempalace |
palace data (drawers, knowledge graph, embeddings) |
devbox-chroma-cache |
/home/developer/.cache/chroma |
ChromaDB embedding model cache (~80 MB, can be rebuilt) |
User-installed pi packages
NPM_CONFIG_PREFIX is set inside the container to /home/developer/.pi/npm-global. Anything you pi install npm:<pkg> or npm install -g lands on the devbox-pi-config named volume — survives container recreation and image rebuilds. A user-installed pi wins over the baked one via PATH order, so you can pin a different pi version without rebuilding the image.
Source
- This image: https://gitea.jordbo.se/joakimp/pi-devbox
- pi: https://github.com/earendil-works/pi
- pi-toolkit: https://gitea.jordbo.se/joakimp/pi-toolkit
- pi-extensions: https://gitea.jordbo.se/joakimp/pi-extensions
- MemPalace: https://github.com/MemPalace/mempalace
License
MIT (the image; pi and the bundled tools each carry their own licenses). See
LICENSE and THIRD_PARTY.md in the source repo.