From 973c2efd5c2dce5eff022c34cd8da341b7c78220 Mon Sep 17 00:00:00 2001 From: Joakim Persson Date: Fri, 15 May 2026 17:58:06 +0200 Subject: [PATCH] Expand README + tweak DOCKER_HUB.md for users not cloning the repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README rewrite: - Two quick-start paths: 'no git clone' (curl docker-compose.yml + .env.example) and 'with git clone' for hackers/forkers - New 'Authentication' section with subsections per provider (Anthropic, OpenAI, Gemini, AWS Bedrock static, AWS Bedrock SSO). AWS SSO path documents the ~/.aws bind-mount. - Persistent state expanded: 5-row volume table + optional volumes table. Annotated what survives what. - Configuration reference: full .env table. - Versioning, building from source (with build args table), troubleshooting FAQ, related projects, license. - 11 kB total — comprehensive but readable. DOCKER_HUB.md tweaks: - Quick-start now has a 'no git clone' path (curl two files), pointing users at the gitea README for the full setup guide. The git-clone path was overkill for the 90% case (just want to docker run). - Explicit link to gitea README at the end of the quick-start block. --- DOCKER_HUB.md | 19 ++-- README.md | 269 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 247 insertions(+), 41 deletions(-) diff --git a/DOCKER_HUB.md b/DOCKER_HUB.md index 008642d..8bf1036 100644 --- a/DOCKER_HUB.md +++ b/DOCKER_HUB.md @@ -13,24 +13,29 @@ Multi-arch: `linux/amd64`, `linux/arm64`. ## Quick start +One-shot, no persistence: + ```bash 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 persistent state (settings, bash history, neovim plugins, mempalace data) and a full dev workflow, use docker-compose: +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: ```bash -git clone https://gitea.jordbo.se/joakimp/pi-devbox -cd pi-devbox -cp .env.example .env # edit WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL, etc -docker compose run --rm devbox -# inside the container: -pi +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: **** + ## What's inside Inherited from [opencode-devbox base](https://hub.docker.com/r/joakimp/opencode-devbox): diff --git a/README.md b/README.md index fd0cd4c..c0a7036 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,259 @@ # pi-devbox -A Docker container image with [pi coding-agent](https://github.com/earendil-works/pi) pre-installed, built on the [opencode-devbox](https://gitea.jordbo.se/joakimp/opencode-devbox) base image. +A Docker container with [pi coding-agent](https://github.com/earendil-works/pi) pre-installed, built on the [opencode-devbox](https://gitea.jordbo.se/joakimp/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`](https://hub.docker.com/r/joakimp/pi-devbox) · multi-arch (amd64 + arm64) +> **Source:** [gitea.jordbo.se/joakimp/pi-devbox](https://gitea.jordbo.se/joakimp/pi-devbox) + +--- ## What's inside -Built on `opencode-devbox:base-latest`, which provides: +Inherited from `opencode-devbox:base-latest`: -- **Debian trixie** (stable base) +- **Debian trixie** (current stable) - **Node.js** (LTS), **uv** (Python), **rustup** (Rust on-demand) -- **AWS CLI** v2 -- **MemPalace** + MCP server (persistent agent memory across sessions) +- **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, git-lfs, make +- **Dev tools**: neovim (LazyVim), tmux, bat, eza, fzf, zoxide, ripgrep, jq, git-lfs, make - **Shell**: bash with history tuning, prefix-search, fzf/zoxide integration -This image adds: +Added by pi-devbox: -- **pi** (`@earendil-works/pi-coding-agent`) — baked at `/usr/bin/pi` -- **pi-toolkit** — keybindings, env loader, settings template (cloned to `/opt/pi-toolkit`) -- **pi-extensions** — ext-toggle, todo, ssh-controlmaster, notify, git-checkpoint, mcp-loader, confirm-destructive (cloned to `/opt/pi-extensions`) -- **mempalace bridge** — `mempalace.ts` extension symlinked from `/opt/mempalace-toolkit` +- **pi** ([`@earendil-works/pi-coding-agent`](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) — baked at `/usr/bin/pi`, version pinned at build time +- **[pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit)** — mosh/tmux-friendly keybindings (Shift+Enter, Ctrl+J, Alt+J newline), AWS env loader, settings template +- **[pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions)** — 7 extensions: `ext-toggle`, `mcp-loader`, `todo`, `ssh-controlmaster`, `notify`, `git-checkpoint`, `confirm-destructive` +- **mempalace bridge** — auto-symlinked MCP extension so pi reads/writes the same palace as opencode -## Quick start +The entrypoint deploys 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: ```bash -cp .env.example .env -# edit .env — set WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL -docker compose run --rm devbox -# inside the container: -pi +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): + +```bash +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: + +```bash +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) + +```ini +ANTHROPIC_API_KEY=sk-ant-... +``` + +Generate a key at . + +### OpenAI + +```ini +OPENAI_API_KEY=sk-... +``` + +### Google Gemini + +```ini +GEMINI_API_KEY=... +``` + +### AWS Bedrock (e.g. Claude on Bedrock) + +Two paths — pick one: + +**A) Static credentials** (simplest, lower-trust environments only): + +```ini +AWS_REGION=eu-west-1 +AWS_ACCESS_KEY_ID=AKIA... +AWS_SECRET_ACCESS_KEY=... +``` + +**B) AWS SSO** (recommended for corporate AWS, requires mounting `~/.aws`): + +```ini +AWS_REGION=eu-west-1 +AWS_PROFILE=your-profile +``` + +Then in your `docker-compose.yml`, uncomment the `~/.aws` bind-mount: + +```yaml +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: + +```bash +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): . + +--- + +## 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`](https://gitea.jordbo.se/joakimp/pi-devbox/src/branch/main/.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 | +| `LANG` / `LANGUAGE` / `LC_ALL` | `en_US.UTF-8` | Locale override | + +--- + ## Versioning -Tags follow the pi npm version: `v0.74.0`, `v0.75.0`, etc. -`latest` always points at the most recent release. +Tags follow the pi npm package version: `v0.74.0`, `v0.75.0`, … `latest` always points at the most recent successful release. -## Persistence +Container-level rebuilds on the same pi version (security updates, base bumps, fixes) get a letter suffix: `v0.74.0b`, `v0.74.0c`, … -| Volume | What it holds | -|--------|---------------| -| `devbox-pi-config` | pi settings, extensions toggle state, sessions (`~/.pi/`) | -| `devbox-shell-history` | bash history | -| `devbox-zoxide` | zoxide directory jump history | -| `devbox-nvim-data` | neovim plugins, Mason packages | -| `devbox-uv` | uv Python installs and tool cache | +When the upstream [pi npm package](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) cuts a new version, this image is rebuilt and re-tagged to match. -## User-installed pi packages +--- -`NPM_CONFIG_PREFIX` is set to `/home/developer/.pi/npm-global`, so any `pi install npm:...` or `npm install -g` as the `developer` user lands on the `devbox-pi-config` volume and survives container recreation and image rebuilds. A user-installed pi wins over the baked binary via `PATH` order. +## Building from source -## Source +If you want to pin a specific pi version, change the base image, or hack on the Dockerfile: -- [pi-devbox](https://gitea.jordbo.se/joakimp/pi-devbox) — this repo -- [opencode-devbox](https://gitea.jordbo.se/joakimp/opencode-devbox) — base image source -- [pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit) -- [pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions) +```bash +git clone https://gitea.jordbo.se/joakimp/pi-devbox +cd pi-devbox + +# Edit Dockerfile or override via build args: +docker compose build \ + --build-arg PI_VERSION=0.73.0 \ + --build-arg BASE_IMAGE=joakimp/opencode-devbox:base-latest + +docker compose up -d +``` + +Build args supported: + +| Arg | Default | Effect | +|---|---|---| +| `BASE_IMAGE` | `joakimp/opencode-devbox:base-latest` | Parent image — set to `joakimp/opencode-devbox:base-` for reproducible builds | +| `PI_VERSION` | `latest` | npm version of `@earendil-works/pi-coding-agent` | +| `PI_TOOLKIT_REF` | `main` | Git ref for [pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit) | +| `PI_EXTENSIONS_REF` | `main` | Git ref for [pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions) | + +--- + +## 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/.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. + +--- + +## Related + +- **[opencode-devbox](https://gitea.jordbo.se/joakimp/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](https://gitea.jordbo.se/joakimp/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](https://gitea.jordbo.se/joakimp/pi-extensions)** — extension source. Same install pattern. +- **[mempalace-toolkit](https://gitea.jordbo.se/joakimp/mempalace-toolkit)** — MemPalace bring-up. The `mempalace.ts` extension symlinked into `~/.pi/agent/extensions/` comes from here. +- **[pi (upstream)](https://github.com/earendil-works/pi)** — the coding-agent itself. + +--- + +## License + +MIT (this image and its source). Pi and the bundled tools each carry their own licenses.