Decision: keep pi 1.0.0's default (tuiMode "fullscreen"). No tuiMode is baked,
so the image follows upstream rather than pinning the fleet to either mode -
but "we inherited a changed default" is only acceptable if the revert is
written down, so it now is.
README gains a "Terminal UI mode" section ahead of the pi-atelier section,
because the two interact. It gives all three scopes, taken from pi 1.0.0's own
docs/settings.md and docs/cli.md rather than from the changelog prose:
- permanent: "tuiMode": "regular" in ~/.pi/agent/settings.json
- one session: pi --tui-mode regular (the flag is real: cli.md:221)
- one project: the same key in .pi/settings.json, which overrides the agent
directory
It also documents the four related settings (fullscreenExitOutput,
fullscreenScrollbar, fullscreenCopyOnSelect, fullscreenWheelScrollLines) and
two things specific to this image:
- tmux: fullscreen uses the alternate screen, so tmux copy-mode shows the
pane history AROUND pi, not pi's transcript. That is the concrete reason
someone here would want "regular" back.
- fullscreenWheelScrollLines "auto" behaves differently over SSH (caps fast
wheel spins at 6 lines/event) than in a local macOS terminal (1 line) -
worth naming because this container is normally driven over SSH.
- pi-atelier works in BOTH modes (upstream has handled regular vs fullscreen
renderers separately since pi 0.84), so reverting costs nothing. Stated so
nobody assumes the sidebar is the price of the old scrollback.
The python3 merge snippet in that section was RUN before being documented:
against a realistic settings.json under an overridden HOME, twice, confirming
it is idempotent and preserves sibling keys including nested objects and the
_comment fields the seeded file uses. Documented code that has never been
executed is a guess.
DOCKER_HUB.md gets a short version of the same note, because CI reads it from
the TAG and POSTs it to Docker Hub as full_description - a behaviour change
this visible should not require reading the repo to undo.
Gates: doc-drift 23 OK / 0 DRIFT / 0 SKIP / 0 FAIL; base-hash, workflow-shell,
skill-floor, lint-shell all rc=0.
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.23 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.25 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.17 GB | Base layer alias (internal building block; pull :latest instead) |
joakimp/pi-devbox:base-<hash> |
amd64, arm64 | ~1.17 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.
Terminal UI mode — fullscreen by default. pi 1.0.0 made the TUI fullscreen, and this image adopts upstream's default. Fullscreen uses the terminal's alternate screen, so the transcript no longer lands in your terminal's (or tmux's) native scrollback. To get the previous behaviour back, set "tuiMode": "regular" in ~/.pi/agent/settings.json, or pass pi --tui-mode regular for a single session. The bundled pi-atelier sidebar works in both modes. See the README for the related fullscreenExitOutput / fullscreenScrollbar / fullscreenCopyOnSelect / fullscreenWheelScrollLines settings — the last one behaves differently over SSH, which is how this container is usually driven.
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, sqlite3, bc/dc, column
- 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 v24 LTS + 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.