pi-devbox

A Docker container with pi coding-agent pre-installed, built on the opencode-devbox base image. Persistent state, full dev toolchain, MemPalace memory, and provider-agnostic LLM auth — in one docker compose run.

Hub: joakimp/pi-devbox · multi-arch (amd64 + arm64) Source: gitea.jordbo.se/joakimp/pi-devbox


What's inside

pi-devbox is a thin re-brand of the pi-only build — it FROMs joakimp/pi-devbox:base-pi-only and adds no layers of its own. That base build is produced by opencode-devbox's CI (from opencode-devbox/Dockerfile.variant with INSTALL_OPENCODE=false, the single source of truth for the pi install + companions) but is published into this repo as the internal building-block tag base-pi-onlynot under opencode-devbox, so an "opencode-devbox" tag never ships without opencode. Everything below is inherited from that build, which is lean and pi-focused — no opencode.

Base tooling:

  • Debian trixie (current stable)
  • Node.js (LTS), uv (Python), rustup (Rust on-demand)
  • AWS CLI v2 (with Bedrock support)
  • MemPalace + MCP server — persistent agent memory across sessions; queryable via mempalace_* tools inside pi
  • Gitea MCP server
  • Dev tools: neovim (LazyVim), tmux, bat, eza, fzf, zoxide, ripgrep, jq, git-lfs, make
  • Shell: bash with history tuning, prefix-search, fzf/zoxide integration
  • Host-OS-agnostic LAN access — on VM-backed hosts (macOS OrbStack / Docker Desktop) the entrypoint sets up the host as an SSH jump so you can reach LAN peers (dssh alias; DEVBOX_LAN_ACCESS/HOST_SSH_USER env). No-op on native Linux.

pi and companions:

  • pi (@earendil-works/pi-coding-agent) — baked at /usr/bin/pi, version pinned by the pi-only base build
  • pi-toolkit — mosh/tmux-friendly keybindings (Shift+Enter, Ctrl+J, Alt+J newline), AWS env loader, settings template
  • pi-extensions — 7 extensions: ext-toggle, mcp-loader, todo, ssh-controlmaster, notify, git-checkpoint, confirm-destructive
  • fork tool (pi-fork) and recall tool (pi-observational-memory) — baked into /opt and registered at runtime
  • mempalace bridge — auto-symlinked MCP extension so pi reads/writes the same palace as opencode-devbox's palace

(opencode itself is not included — that's the difference from opencode-devbox:latest-with-pi. If you want both opencode and pi in one image, use that variant instead.)

The entrypoint deploys/registers all of these on first container start. Idempotent and preserves user edits.


Quick start (no git clone)

If you just want to run pi-devbox and don't plan to modify the source, grab the two template files and go:

mkdir -p ~/pi-devbox && cd ~/pi-devbox

# Pull the docker-compose.yml and .env template
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 — at minimum set WORKSPACE_PATH, an LLM API key, and your git identity
$EDITOR .env

# Pull and run pi
docker compose run --rm devbox pi

docker compose run --rm devbox (no command) drops you into bash; you can then run pi, aws sso login, etc. manually.

To attach a second terminal to the same container (e.g. shell while pi is running):

docker compose exec -u developer devbox bash

Quick start (with git clone)

If you want to follow upstream changes, run a customized fork, or rebuild the image yourself:

git clone https://gitea.jordbo.se/joakimp/pi-devbox
cd pi-devbox
cp .env.example .env
$EDITOR .env
docker compose run --rm devbox pi

Authentication

pi reads provider credentials from environment variables, which the container picks up from .env automatically.

Anthropic (Claude)

ANTHROPIC_API_KEY=sk-ant-...

Generate a key at https://console.anthropic.com/settings/keys.

OpenAI

OPENAI_API_KEY=sk-...

Google Gemini

GEMINI_API_KEY=...

AWS Bedrock (e.g. Claude on Bedrock)

Two paths — pick one:

A) Static credentials (simplest, lower-trust environments only):

AWS_REGION=eu-west-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...

B) AWS SSO (recommended for corporate AWS, requires mounting ~/.aws):

AWS_REGION=eu-west-1
AWS_PROFILE=your-profile

Then in your docker-compose.yml, uncomment the ~/.aws bind-mount:

volumes:
  - ~/.aws:/home/developer/.aws

Inside the container, run aws sso login once per session. The token cache lives on the bind-mount, so subsequent pi invocations pick it up automatically. The pi-toolkit's pi-env.zsh (deployed to ~/.config/pi/) auto-sources AWS_PROFILE/AWS_REGION whenever a shell starts.

First-run pi configuration

On first start, pi reads ~/.pi/agent/settings.json (auto-bootstrapped from the pi-toolkit template). Edit it inside the container to pick a default provider/model:

docker compose exec -u developer devbox bash
$EDITOR ~/.pi/agent/settings.json

The file is rewritten by pi at runtime (e.g. lastChangelogVersion), so it lives on the devbox-pi-config named volume — your edits persist across container recreation.

For pi's full configuration model (provider list, model overrides, MCP integration, themes, extensions): https://github.com/earendil-works/pi#configuration.


Persistent state

Persistent state is what makes the difference between "use this once" and "make it my long-term coding environment". Everything important survives docker compose down and image upgrades; only docker compose down -v wipes the volumes.

Volume Mount point What survives Notes
devbox-pi-config /home/developer/.pi/ pi settings.json, extension toggles, sessions, user-installed pi packages NPM_CONFIG_PREFIX set inside the container so pi install npm:… and npm install -g lands here automatically
devbox-shell-history /home/developer/.cache/bash bash history Across container recreate
devbox-zoxide /home/developer/.local/share/zoxide zoxide directory jump history The z/zi shortcuts remember where you've been
devbox-nvim-data /home/developer/.local/share/nvim neovim plugin & Mason package state LazyVim plugins persist
devbox-uv /home/developer/.local/share/uv uv-managed Python installs and tool cache uv tool install results live here

Optional persistent volumes

These are commented out in docker-compose.yml by default. Uncomment them if you want the corresponding state to persist:

Volume Mount point What survives
devbox-palace /home/developer/.mempalace MemPalace data — drawers, knowledge graph, embeddings. Treat as primary storage if you rely on agent memory.
devbox-chroma-cache /home/developer/.cache/chroma ChromaDB embedding model cache (~80 MB; disposable, re-downloads in seconds)

Workspace bind mount

/workspace is bind-mounted from WORKSPACE_PATH on the host (default ~/projects). Source code never lives inside the container — your editor on the host and pi inside the container see the same files.

SSH keys (read-only)

~/.ssh is mounted read-only at /home/developer/.ssh for git push/pull. The container does not write to it.


Configuration reference

All config flows through .env. The full list (with annotations) is in .env.example. Here's the most relevant subset:

Variable Default Purpose
WORKSPACE_PATH ~/projects Host path mounted as /workspace
SSH_KEY_PATH ~/.ssh Host path for SSH keys (read-only)
GIT_USER_NAME (empty) Sets git config --global user.name inside container
GIT_USER_EMAIL (empty) Sets git config --global user.email inside container
ANTHROPIC_API_KEY (unset) Anthropic provider auth
OPENAI_API_KEY (unset) OpenAI provider auth
GEMINI_API_KEY (unset) Google Gemini auth
AWS_PROFILE / AWS_REGION (unset) AWS Bedrock SSO flow
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY (unset) AWS Bedrock static creds
GITEA_ACCESS_TOKEN / GITEA_HOST (unset) Gitea MCP server (optional)
GITHUB_PERSONAL_ACCESS_TOKEN (unset) GitHub MCP server / git ops over HTTPS
DEVBOX_LAN_ACCESS auto LAN-access mode: auto (jump only on VM-backed hosts), jump, off
HOST_SSH_USER (unset) Host username for the LAN SSH jump (see opencode-devbox README)
LANG / LANGUAGE / LC_ALL en_US.UTF-8 Locale override

Versioning

Tags follow the pi npm package version: v0.74.0, v0.75.0, … latest always points at the most recent successful release.

Container-level rebuilds on the same pi version (security updates, base bumps, fixes) get a letter suffix: v0.74.0b, v0.74.0c, …

The pi binary is inherited from joakimp/pi-devbox:base-pi-only, so a release of this image must be preceded by an opencode-devbox release that bakes the target pi version into base-pi-only. The smoke test enforces this (it asserts pi --version matches the tag).


Building from source

This image is a thin re-brand of the pi-only variant, so building it just pulls the base. To pin a specific pi-only build or hack on it:

git clone https://gitea.jordbo.se/joakimp/pi-devbox
cd pi-devbox

# Default tracks base-pi-only; override BASE_IMAGE to pin a build:
docker compose build \
  --build-arg BASE_IMAGE=joakimp/pi-devbox:base-pi-only-v1.15.13c

docker compose up -d

To change the pi version, the pi extensions, or the install logic, edit opencode-devbox/Dockerfile.variant (the single source of truth) and release opencode-devbox — not this repo.

Build args supported:

Arg Default Effect
BASE_IMAGE joakimp/pi-devbox:base-pi-only Parent image (internal building-block tag) — set to a :base-pi-only-vX.Y.Z tag or a digest for reproducible builds

Troubleshooting

pi --version works but pi exits immediately. First-run config probably hasn't been done. docker compose exec -u developer devbox bash, edit ~/.pi/agent/settings.json, ensure a provider is set and the matching API key is exported.

AWS SSO token expired. aws sso login from inside the container. The token cache is on the ~/.aws bind-mount, so it persists; expiration is the issue.

Anthropic 401 / OpenAI 401. Check the .env value made it in: docker compose exec devbox env | grep ANTHROPIC (etc).

pi prompts for an extension/MCP server you don't recognize. Either toggle it off via /ext inside pi, or rename the file: mv ~/.pi/agent/extensions/<name>.ts{,.off}.

Container won't start, error about /workspace. WORKSPACE_PATH in .env doesn't exist on the host. Create the directory or fix the path.

Pi-toolkit symlinks lost after docker compose down -v. That's expected — -v wipes named volumes. Don't do it unless you mean it. Container recreation without -v (the default) preserves all state.


  • opencode-devbox — the base image. Use this if you want both opencode and pi (it has a latest-with-pi variant) or just opencode.
  • pi-toolkit — keybindings, env loader, settings template. Cloned into /opt/pi-toolkit at image build time and install.sh runs on container start.
  • pi-extensions — extension source. Same install pattern.
  • mempalace-toolkit — MemPalace bring-up. The mempalace.ts extension symlinked into ~/.pi/agent/extensions/ comes from here.
  • pi (upstream) — the coding-agent itself.

License

MIT (this image and its source). Pi and the bundled tools each carry their own licenses.

S
Description
pi coding-agent container built on opencode-devbox base
Readme 248 KiB
Languages
Shell 76.3%
Dockerfile 23.7%