docs: rewrite DOCKER_HUB.md for v1.0.0 reality + auto-inject pi version

The Hub description still described the pre-v1.0.0 reality (tags follow
pi npm version, builds FROM joakimp/pi-devbox:base-pi-only, opencode-
devbox lineage as source of truth) — none of that has been true since
v1.0.0 decoupled. End users on Hub got a misleading story.

DOCKER_HUB.md changes:
- Versioning section rewritten: semver from v1.0.0, with a deprecation
  note for the pre-v1.0.0 v{pi_version}[letter] scheme.
- New 'Build pipeline' section briefly explains the two-phase
  base/variant content-addressed structure so users understand what
  base-<hash> and base-latest tags are for.
- New 'Document and image tooling' section (pandoc, graphviz,
  imagemagick) added since these are new in v1.0.0 and broadly useful.
- Tealdeer noted (vs the old Node tldr).
- Tmux 0-indexing called out (relevant for future :latest-studio
  variant).
- Removed all 'pi-only build' / 'FROM base-pi-only' / 'opencode-devbox
  bakes the pi version' framing — pi-devbox is now self-contained.
- New {{PI_VERSION}} placeholder in 4 locations so the Hub description
  always shows which pi is in :latest.

Workflow change:
- update-description step now substitutes {{PI_VERSION}} placeholders
  in DOCKER_HUB.md before sending to Hub. PI_VERSION comes from the
  resolve-versions output (same one baked into the image), so the page
  and image can never disagree. Sanity-check fails the step if any
  unsubstituted placeholder remains.
This commit is contained in:
pi
2026-06-10 12:34:37 +02:00
parent 8b69b3625b
commit efd254f4e6
2 changed files with 92 additions and 36 deletions
+15 -2
View File
@@ -409,7 +409,20 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Update Docker Hub description - name: Update Docker Hub description
env:
PI_VERSION: ${{ needs.resolve-versions.outputs.pi_version }}
run: | run: |
# Substitute {{PI_VERSION}} placeholders in DOCKER_HUB.md so the
# Hub page always shows which pi version is in :latest. The
# placeholder lives in DOCKER_HUB.md (committed); CI fills it
# at publish time using the same resolved version that was
# baked into the variant image. No drift between page and image.
cp DOCKER_HUB.md /tmp/hub-full.md
sed -i "s/{{PI_VERSION}}/${PI_VERSION}/g" /tmp/hub-full.md
if grep -q '{{PI_VERSION}}' /tmp/hub-full.md; then
echo "::error::DOCKER_HUB.md still contains unsubstituted {{PI_VERSION}} markers"
exit 1
fi
TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \ TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"identifier":"${{ vars.DOCKERHUB_USERNAME }}","secret":"${{ secrets.DOCKERHUB_TOKEN }}"}' \ -d '{"identifier":"${{ vars.DOCKERHUB_USERNAME }}","secret":"${{ secrets.DOCKERHUB_TOKEN }}"}' \
@@ -419,7 +432,7 @@ jobs:
exit 1 exit 1
fi fi
HTTP_CODE=$(jq -n \ HTTP_CODE=$(jq -n \
--rawfile full DOCKER_HUB.md \ --rawfile full /tmp/hub-full.md \
--arg short "Linux container with the pi coding-agent, MemPalace, and curated dev tooling." \ --arg short "Linux container with the pi coding-agent, MemPalace, and curated dev tooling." \
'{"full_description": $full, "description": $short}' | \ '{"full_description": $full, "description": $short}' | \
curl -s -o /tmp/hub-response.txt -w "%{http_code}" -X PATCH \ curl -s -o /tmp/hub-response.txt -w "%{http_code}" -X PATCH \
@@ -433,4 +446,4 @@ jobs:
echo "::error::Docker Hub description update failed with HTTP $HTTP_CODE" echo "::error::Docker Hub description update failed with HTTP $HTTP_CODE"
exit 1 exit 1
fi fi
echo "Description updated." echo "Description updated (pi version: ${PI_VERSION})."
+77 -34
View File
@@ -1,15 +1,17 @@
# pi-devbox # pi-devbox
A Docker container with [pi coding-agent](https://github.com/earendil-works/pi) pre-installed, built on top of [opencode-devbox](https://hub.docker.com/r/joakimp/opencode-devbox)'s base image. Pi gets a fully-loaded development environment in one `docker run`. A self-contained Docker container for the [pi coding-agent](https://github.com/earendil-works/pi) — pi + companion repos + MemPalace + a curated set of dev tooling, ready to run.
> **Current `:latest` ships pi `{{PI_VERSION}}`** (resolved at build time; see [Versioning](#versioning)).
## Image variants ## Image variants
| Tag | Size (compressed) | What you get | | Tag | Architectures | Size (compressed) | What you get |
|---|---|---| |---|---|---|---|
| `joakimp/pi-devbox:latest` | ~700 MB | Pi + companion repos, on top of the opencode-devbox base | | `joakimp/pi-devbox:latest` | amd64, arm64 | ~1.1 GB | Self-contained: base + pi `{{PI_VERSION}}` + companions |
| `joakimp/pi-devbox:vX.Y.Z` | same | Pinned pi version (tracks the [pi npm package version](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) | | `joakimp/pi-devbox:vX.Y.Z` | amd64, arm64 | same | Pinned semver release |
| `joakimp/pi-devbox:base-latest` | amd64, arm64 | ~1.0 GB | Base layer alias (internal building block; pull `:latest` instead) |
Multi-arch: `linux/amd64`, `linux/arm64`. | `joakimp/pi-devbox:base-<hash>` | amd64, arm64 | ~1.0 GB | Content-addressed base; immutable. Stable parent for variant rebuilds. |
## Quick start ## Quick start
@@ -38,42 +40,82 @@ Full setup guide — authentication for each provider (Anthropic, OpenAI, Gemini
## What's inside ## What's inside
pi-devbox is a re-brand of the **pi-only build** — it builds ### pi and companions
`FROM joakimp/pi-devbox:base-pi-only` and adds no layers of its own. That
building-block tag is produced by opencode-devbox's CI (from
`Dockerfile.variant` with `INSTALL_OPENCODE=false`) but published here, in the
pi-devbox repo, so an opencode-devbox tag never ships without opencode.
The pi-only build is lean
and pi-focused (no opencode — use `opencode-devbox:latest-with-pi` if you want
both).
Everything below is inherited from that single source of truth.
Base tooling: - **pi `{{PI_VERSION}}`** ([`@earendil-works/pi-coding-agent`](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) — installed at `/usr/bin/pi`
- **Debian trixie** (latest stable)
- **Node.js** (LTS), **uv** (Python tooling), **rustup** (Rust on-demand)
- **AWS CLI v2** + AWS Bedrock-ready config
- **MemPalace** + MCP server — persistent agent memory across sessions, queryable via `mempalace_*` tools inside pi
- **Gitea MCP** server
- **Dev tools**: neovim (LazyVim defaults), tmux, bat, eza, fzf, zoxide, ripgrep, git-lfs, make
- **Shell**: bash with history tuning, prefix-search bindings, fzf/zoxide integration
- **Host-OS-agnostic LAN access** — on VM-backed hosts (macOS OrbStack / Docker Desktop) the host is set up as an SSH jump to reach LAN peers (`dssh` alias; `DEVBOX_LAN_ACCESS`/`HOST_SSH_USER`). No-op on native Linux.
pi and companions:
- **pi** ([`@earendil-works/pi-coding-agent`](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) — baked at `/usr/bin/pi`, version set by the pi-only base build
- **[pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit)** — keybindings (mosh/tmux-friendly Shift+Enter, Ctrl+J, Alt+J newline bindings), AWS env loader, settings template - **[pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit)** — keybindings (mosh/tmux-friendly Shift+Enter, Ctrl+J, Alt+J newline bindings), AWS env loader, settings template
- **[pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions)** — 7 user-facing extensions: `ext-toggle`, `mcp-loader`, `todo`, `ssh-controlmaster`, `notify`, `git-checkpoint`, `confirm-destructive` - **[pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions)** — 7 user-facing extensions: `ext-toggle`, `mcp-loader`, `todo`, `ssh-controlmaster`, `notify`, `git-checkpoint`, `confirm-destructive`
- **`fork`** ([pi-fork](https://github.com/elpapi42/pi-fork)) and **`recall`** ([pi-observational-memory](https://github.com/elpapi42/pi-observational-memory)) tools - **`fork`** ([pi-fork](https://github.com/elpapi42/pi-fork)) and **`recall`** ([pi-observational-memory](https://github.com/elpapi42/pi-observational-memory)) tools
- **mempalace bridge** — MCP extension auto-symlinked so pi can read/write the same palace as opencode-devbox - **mempalace bridge** — MCP extension auto-symlinked so pi reads/writes the host-mounted palace
The entrypoint deploys/registers all of these on first container start. Re-running is idempotent and preserves user edits. 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 `~/.mempalace` and 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.
- **graphviz** (`dot`) — diagram rendering pipelines
- **imagemagick** (`magick`) — image conversion / resizing
### Modern CLI tooling
- **Editor**: neovim (LazyVim defaults), 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 --update` once 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:
```bash
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-init` is on PATH; install toolchains on demand
- **Go** — opt-in via `--build-arg INSTALL_GO=true` if 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 **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 ## Versioning
Tags follow the pi npm version: `v0.74.0`, `v0.75.0`, etc. `latest` always points at the most recent release. The pi binary is inherited from `joakimp/pi-devbox:base-pi-only`, so each release follows an opencode-devbox release that bakes the target pi version. (`base-pi-only` is an internal building-block tag — pull `latest` or a `vX.Y.Z` tag instead.) From v1.0.0 onward, pi-devbox uses **semver**:
For container-level rebuilds on the same pi version (security updates, base bumps, fixes) the tag gets a letter suffix: `v0.74.0b`, `v0.74.0c`, … - **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-only` variant).
- **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:
1. **Base** (`Dockerfile.base`) → `base-<hash>` tag, content-addressed over `Dockerfile.base` + `rootfs/` + `entrypoint*.sh`. Rebuilt only when those change.
2. **Variant** (`Dockerfile.variant`) → `:latest` and `:vX.Y.Z`. FROMs the base, adds the pi install + companions.
`base-latest` is an alias of the most recent base.
## Persistent state ## Persistent state
@@ -86,6 +128,7 @@ User edits and pi-installed packages survive container recreation when you mount
| `devbox-zoxide` | `/home/developer/.local/share/zoxide` | zoxide directory jump database | | `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-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-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): Optional volumes for MemPalace (commented out by default — uncomment in `docker-compose.yml` to persist conversation memory across restarts):
@@ -101,10 +144,10 @@ Optional volumes for MemPalace (commented out by default — uncomment in `docke
## Source ## Source
- **This image**: https://gitea.jordbo.se/joakimp/pi-devbox - **This image**: https://gitea.jordbo.se/joakimp/pi-devbox
- **Base image**: https://gitea.jordbo.se/joakimp/opencode-devbox (Hub: `joakimp/opencode-devbox`)
- **pi**: https://github.com/earendil-works/pi - **pi**: https://github.com/earendil-works/pi
- **pi-toolkit**: https://gitea.jordbo.se/joakimp/pi-toolkit - **pi-toolkit**: https://gitea.jordbo.se/joakimp/pi-toolkit
- **pi-extensions**: https://gitea.jordbo.se/joakimp/pi-extensions - **pi-extensions**: https://gitea.jordbo.se/joakimp/pi-extensions
- **MemPalace**: https://github.com/joakimp/mempalace
## License ## License