v2.0.0: remove pi, relocate npm-global prefix, bump opencode 1.17.2->1.17.4
Validate / base-change-warning (push) Successful in 14s
Validate / docs-check (push) Successful in 13s
Publish Docker Image / resolve-versions (push) Successful in 8s
Publish Docker Image / base-decide (push) Successful in 13s
Validate / validate-omos (push) Successful in 12m42s
Validate / validate-base (push) Successful in 13m39s
Publish Docker Image / build-base (push) Successful in 44m17s
Publish Docker Image / smoke-base (push) Successful in 3m46s
Publish Docker Image / smoke-omos (push) Successful in 5m54s
Publish Docker Image / build-variant-base (push) Successful in 18m11s
Publish Docker Image / build-variant-omos (push) Successful in 19m34s
Publish Docker Image / promote-base-latest (push) Successful in 9s
Publish Docker Image / update-description (push) Successful in 15s
Validate / base-change-warning (push) Successful in 14s
Validate / docs-check (push) Successful in 13s
Publish Docker Image / resolve-versions (push) Successful in 8s
Publish Docker Image / base-decide (push) Successful in 13s
Validate / validate-omos (push) Successful in 12m42s
Validate / validate-base (push) Successful in 13m39s
Publish Docker Image / build-base (push) Successful in 44m17s
Publish Docker Image / smoke-base (push) Successful in 3m46s
Publish Docker Image / smoke-omos (push) Successful in 5m54s
Publish Docker Image / build-variant-base (push) Successful in 18m11s
Publish Docker Image / build-variant-omos (push) Successful in 19m34s
Publish Docker Image / promote-base-latest (push) Successful in 9s
Publish Docker Image / update-description (push) Successful in 15s
PR-5 (per docs/CLEANUP-v2.0.0.md). Major release with two breaking changes:
1. pi fully removed (deprecated in v1.17.2). Gone: INSTALL_PI + all PI_*
build args; with-pi/omos-with-pi/pi-only variants; base-pi-only publish
job; all ~/.pi entrypoint wiring; the 3 pi smoke/validate/build-variant
CI jobs. Only base + omos variants remain (4 tags/release).
2. NPM_CONFIG_PREFIX relocated ~/.pi/npm-global -> ~/.config/opencode/npm-global
(persistent in both compose files). entrypoint-user.sh gains a one-time
migration shim that copies old global npm packages forward.
Also: opencode 1.17.2->1.17.4; DOCKER_HUB.md gains {{OPENCODE_VERSION}}
placeholder filled by CI at publish time (mirrors pi-devbox); full docs
drift sweep across README/AGENTS/.gitea-README/.env.example/manual-host-publish;
DOCKER_HUB.md regenerated + --check passes; both workflows YAML-valid;
all shell scripts pass bash -n.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
Portable AI developer environment in a Docker container. Run [opencode](https://opencode.ai) on any Docker-capable machine with configurable LLM providers, dev tools, and host filesystem access.
|
||||
|
||||
> **Looking for pi?** As of **v2.0.0** the [pi](https://github.com/earendil-works/pi) coding-agent is no longer bundled here. It now ships as its own self-contained image, **[`joakimp/pi-devbox`](https://gitea.jordbo.se/joakimp/pi-devbox)** (also on [Docker Hub](https://hub.docker.com/r/joakimp/pi-devbox)), built on a shared Debian base and able to share this image's mempalace palace. Pull `joakimp/pi-devbox:latest` instead of the old `*-with-pi` / `pi-only` tags. See the [v2.0.0 CHANGELOG](CHANGELOG.md) for the migration details (including the `~/.pi/npm-global` → `~/.config/opencode/npm-global` prefix move).
|
||||
|
||||
## Why?
|
||||
|
||||
The official `ghcr.io/anomalyco/opencode` image (now archived) was Alpine-based and minimal — no git, no dev tools, broken PTY support due to musl/glibc incompatibility. This project provides a **Debian-based, production-ready** alternative using the current v1.x release.
|
||||
@@ -25,7 +27,7 @@ $EDITOR .env
|
||||
docker compose run --rm devbox
|
||||
```
|
||||
|
||||
This pulls `joakimp/opencode-devbox:latest` from Docker Hub, mounts `WORKSPACE_PATH` at `/workspace`, and drops you straight into opencode. Use `bash` instead of (no command) to land in a shell first — useful for `aws sso login`, `pi`, `omos`, etc.
|
||||
This pulls `joakimp/opencode-devbox:latest` from Docker Hub, mounts `WORKSPACE_PATH` at `/workspace`, and drops you straight into opencode. Use `bash` instead of (no command) to land in a shell first — useful for `aws sso login`, `omos`, etc.
|
||||
|
||||
**Want to hack on the image itself, follow upstream changes, or rebuild from source?** Clone the repo:
|
||||
|
||||
@@ -187,11 +189,11 @@ Now `dssh my-nas` routes container → host → LAN peer, pulling HostName/User/
|
||||
|
||||
> This ships the **mechanism** only — your specific target hosts are facts about *your* network (and a laptop roams between several), so they live in your own host-side config, never baked into the image. Set `DEVBOX_LAN_ACCESS=off` to disable, or `=jump` to force it (e.g. native Linux with `extra_hosts: ["host.docker.internal:host-gateway"]`).
|
||||
|
||||
#### Gotcha: per-host `ControlPath` and `pi --ssh`
|
||||
#### Gotcha: per-host `ControlPath` and read-only `~/.ssh`
|
||||
|
||||
The base image bakes a `Host *` default (`/etc/ssh/ssh_config.d/00-devbox-controlmaster.conf`) that points `ControlPath` at the writable, per-container `/tmp/sshcm/` (created mode-700 on every start by `entrypoint-user.sh`). Multiplexing therefore works out of the box. **But your bind-mounted `~/.ssh/config` is read first, and SSH uses the first value it sees** — so any per-host block that sets its own `ControlPath` under `~/.ssh/` (a common CGNAT-multiplexing pattern, e.g. `ControlPath ~/.ssh/cm/%r@%h:%p`) **wins, and then fails inside the container** because `~/.ssh` is mounted **read-only** — the master socket can't bind (`cannot bind … Read-only file system`).
|
||||
|
||||
This bites `pi --ssh <host>` especially: the SSH layer fails to establish the master and pi silently falls back to running its `read`/`write`/`edit`/`bash` tools **locally in the container** instead of on the remote (watch for the missing `SSH ⚡` in the status bar — and `hostname` returning the container ID).
|
||||
This bites any in-container tool that opens an SSH connection to a remote host (git over SSH, `rsync`, remote-execution agents): the master fails to establish and the connection either errors or silently degrades.
|
||||
|
||||
**Fix (host-side, one line):** in your host's `~/.ssh/config`, either drop the per-host `ControlPath` (to inherit the writable baked default) or point it at a path that's writable inside the container too:
|
||||
|
||||
@@ -201,7 +203,7 @@ Host my-remote
|
||||
ControlPath /tmp/sshcm/%r@%h:%p # writable on both host and container
|
||||
```
|
||||
|
||||
`/tmp/sshcm/` is also writable on the host (macOS/Linux), so native (non-container) `ssh`/`pi --ssh` from the host keeps working and CGNAT multiplexing is preserved (`ControlMaster`/`ControlPersist` unchanged — only the socket *directory* moves). Note SSH does not create the `ControlPath` parent dir; the container makes `/tmp/sshcm` every start, but on the host run `mkdir -p /tmp/sshcm` once if it doesn't already exist.
|
||||
`/tmp/sshcm/` is also writable on the host (macOS/Linux), so native (non-container) `ssh` from the host keeps working and CGNAT multiplexing is preserved (`ControlMaster`/`ControlPersist` unchanged — only the socket *directory* moves). Note SSH does not create the `ControlPath` parent dir; the container makes `/tmp/sshcm` every start, but on the host run `mkdir -p /tmp/sshcm` once if it doesn't already exist.
|
||||
|
||||
### Custom opencode config
|
||||
|
||||
@@ -420,11 +422,7 @@ docker compose build --build-arg NVIM_VERSION=0.12.1 # pin to a specific versi
|
||||
| `INSTALL_MEMPALACE` | `true` | [MemPalace](https://github.com/MemPalace/mempalace) local AI memory system (~300 MB — disable to shrink image if you don't need MCP memory) |
|
||||
| `INSTALL_MEMPALACE_TOOLKIT` | `true` | [mempalace-toolkit](https://gitea.jordbo.se/joakimp/mempalace-toolkit) bash wrappers (`mempalace-session`, `mempalace-docs`). Cloned at build time from `MEMPALACE_TOOLKIT_REF` (default `main`). Requires `INSTALL_MEMPALACE=true`. |
|
||||
| `INSTALL_OMOS` | `false` | [oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim) multi-agent orchestration (installs Bun and plugin) |
|
||||
| `INSTALL_PI` | `false` | **DEPRECATED (removed in v2.0.0)** — install pi alongside opencode. Use [`joakimp/pi-devbox`](https://gitea.jordbo.se/joakimp/pi-devbox) instead. |
|
||||
| `INSTALL_OPENCODE` | `true` | Install opencode. Set `false` to build a pi-only image (still includes Bun if `INSTALL_OMOS=true`; for a fully stripped pi-only image see the `pi-devbox` repo). **Note: the pi-only path is deprecated and removed in v2.0.0.** |
|
||||
| `INSTALL_PI` | `false` | Install [pi](https://github.com/earendil-works/pi) as alternative/complementary harness. Both clones [pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit) (~5 MB) and [pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions) (~1 MB) into `/opt/`; entrypoint deploys them on container start. ~150 MB total image growth. |
|
||||
| `PI_VERSION` | `latest` | npm version of `@earendil-works/pi-coding-agent`. Floats by default (image rebuild = pi update). |
|
||||
| `PI_TOOLKIT_REF`, `PI_EXTENSIONS_REF` | `main` | Git refs for the toolkit/extensions clones. Pin to a tag/commit for reproducibility. |
|
||||
| `INSTALL_OPENCODE` | `true` | Install opencode. Set `false` to build a base with no harness (still includes Bun if `INSTALL_OMOS=true`). |
|
||||
| `OPENCODE_VERSION` | *(pinned per release)* | opencode npm version. Drives the image tag and is intentionally not floated. |
|
||||
| `NODE_VERSION` | `22` | Node.js major version. Pinned to protect against upstream breaking changes across majors. |
|
||||
| `GOSU_VERSION`, `FZF_VERSION`, `GIT_LFS_VERSION`, `NVIM_VERSION`, `BAT_VERSION`, `EZA_VERSION`, `ZOXIDE_VERSION`, `UV_VERSION`, `GITEA_MCP_VERSION`, `GO_VERSION`, `OMOS_VERSION` | `latest` | All GitHub/Gitea/go.dev-hosted binaries resolve to the newest upstream release at build time. Override with a specific version to pin. Resolved versions are logged in CI output. |
|
||||
@@ -486,92 +484,6 @@ ping all agents
|
||||
|
||||
All six agents should respond if your provider authentication is working.
|
||||
|
||||
## pi (alternative/complementary harness)
|
||||
|
||||
> **⚠ DEPRECATED since v1.17.2 — removed in v2.0.0.** pi support in
|
||||
> opencode-devbox (the `INSTALL_PI` build arg, the `*-with-pi` /
|
||||
> `omos-with-pi` / `pi-only` variants, and the `base-pi-only` tag) is
|
||||
> deprecated. pi now ships as its own self-contained image:
|
||||
> **[`joakimp/pi-devbox`](https://gitea.jordbo.se/joakimp/pi-devbox)** — pull
|
||||
> that directly. The section below documents the legacy path until removal.
|
||||
>
|
||||
> *Migration note for v2.0.0:* the global npm prefix
|
||||
> (`NPM_CONFIG_PREFIX`) will move off the pi-specific `~/.pi/npm-global`
|
||||
> path to a neutral opencode path. Globally `npm install -g`'d tools may
|
||||
> need their volume/PATH refreshed; the v2.0.0 release notes will carry a
|
||||
> one-time migration shim and details.
|
||||
|
||||
[pi](https://github.com/earendil-works/pi) is a lightweight TUI coding-agent that can run alongside opencode in the same container. Both harnesses share the mempalace install and palace data — wing/diary entries created by one are visible to the other.
|
||||
|
||||
### Setup
|
||||
|
||||
Pre-built pi-enabled images are available on Docker Hub as `joakimp/opencode-devbox:latest-with-pi` (base + pi) and `joakimp/opencode-devbox:latest-omos-with-pi` (OMOS + pi). Pulling one of those tags is the fastest path. If you want pi **without** opencode, use the separate, leaner [`joakimp/pi-devbox`](https://gitea.jordbo.se/joakimp/pi-devbox) image instead (it's built from the same `Dockerfile.variant` with `INSTALL_OPENCODE=false`, published in its own repo so an opencode-devbox tag never ships without opencode). Alternatively, build from source:
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
docker compose build --build-arg INSTALL_PI=true
|
||||
# Or: pin a pi version
|
||||
docker compose build --build-arg INSTALL_PI=true --build-arg PI_VERSION=0.73.0
|
||||
# Or: pi-only image (no opencode, smaller)
|
||||
docker compose build --build-arg INSTALL_PI=true --build-arg INSTALL_OPENCODE=false
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
The default `compose run --rm devbox` invocation drops to a login bash so you can choose:
|
||||
|
||||
```bash
|
||||
docker compose run --rm devbox # bash, then `pi` or `opencode` or `aws sso login`
|
||||
docker compose run --rm devbox pi # launch pi directly
|
||||
docker compose run --rm devbox opencode
|
||||
```
|
||||
|
||||
For an attached `compose up -d` container, both harnesses are reachable via `compose exec`:
|
||||
|
||||
```bash
|
||||
docker compose exec -u developer devbox pi
|
||||
docker compose exec -u developer devbox opencode
|
||||
docker compose exec -u developer devbox bash
|
||||
```
|
||||
|
||||
### What gets installed
|
||||
|
||||
- **`pi` CLI** — npm-installed globally at build time. Version pinned by `PI_VERSION`.
|
||||
- **pi-toolkit** — keybindings.json (mosh/tmux newline fixes), pi-env.zsh (AWS env loader), settings.json template. Cloned to `/opt/pi-toolkit`; deployed to `~/.pi/agent/` on first container start.
|
||||
- **pi-extensions** — 7 extensions, cloned to `/opt/pi-extensions` and symlinked into `~/.pi/agent/extensions/`:
|
||||
- `confirm-destructive` — confirm-prompt before dangerous bash commands and session actions.
|
||||
- `ext-toggle` — `/ext` slash command to list and enable/disable extensions at runtime (rename-to-disable; survives `/reload`).
|
||||
- `git-checkpoint` — per-turn `git stash` checkpoint, restorable on `/fork`.
|
||||
- `mcp-loader` — generic MCP server loader. Reads an `mcp` block from `~/.pi/agent/settings.json` (same shape as opencode and Claude Desktop) and connects to each declared server, exposing the tools as native pi tools. Supports both **local stdio** subprocesses (`uvx mcp-searxng`, `gitea-mcp`, …) and **remote streamable-HTTP** servers per MCP spec 2025-03-26 (e.g. `https://mcp.context7.com/mcp`). Adds a `/mcp` slash command for runtime status / toggle (same UX as `/ext`). See [`pi-extensions/AGENTS.md`](https://gitea.jordbo.se/joakimp/pi-extensions/src/branch/main/AGENTS.md) for transport details and the `headers` config for auth tokens.
|
||||
- `notify` — native terminal notification when the agent finishes.
|
||||
- `ssh-controlmaster` — transparent SSH remote execution via persistent ControlMaster socket (when pi is launched with `--ssh user@host`).
|
||||
- `todo` — `todo` tool for the agent + `/todos` for the user.
|
||||
- **mempalace bridge** — separate `mempalace.ts` extension symlinked from the cloned `mempalace-toolkit`. Provides pi's MCP tools for palace search/diary/knowledge-graph with bespoke agent-identity injection from `$MEMPALACE_AGENT_NAME`. Coexists with `mcp-loader` rather than replacing it — don't list `mempalace` in settings.json's `mcp` block too, or you'll get duplicate tool registrations.
|
||||
- **MCP servers (none baked in beyond mempalace)** — the loader registers nothing by default. Add servers by editing `~/.pi/agent/settings.json` and `/reload`. Examples (mcp-searxng for web search, context7 for live library docs) are in the `pi-extensions` README.
|
||||
|
||||
### Persistence
|
||||
|
||||
`~/.pi/` is mounted on the `devbox-pi-config` named volume. Everything below survives container recreate **and** image rebuilds:
|
||||
|
||||
- `~/.pi/agent/settings.json` (provider/model, theme selection, the `mcp` block, and the `packages` array tracking installed pi packages).
|
||||
- `~/.pi/agent/extensions/` (hand-placed extensions and the symlinks deployed by `pi-extensions/install.sh`).
|
||||
- `~/.pi/agent/sessions/`, `~/.pi/agent/auth.json`.
|
||||
- `~/.pi/agent/git/<host>/<path>/` (pi packages installed via `pi install git:...`).
|
||||
- `~/.pi/npm-global/` (pi packages installed via `pi install npm:...`, plus any `npm install -g` invoked as the `developer` user). `NPM_CONFIG_PREFIX` is pre-set in the image, the prefix's `bin/` is on `PATH`, and the directory itself lives on the volume — so user-installed themes, skills, and extensions survive everything short of `docker compose down -v`.
|
||||
|
||||
The **baked** pi binary (and pi-toolkit / pi-extensions repos under `/opt/`) live on the image filesystem, not the volume. Image rebuild is the upgrade path for those — same contract as `OPENCODE_VERSION`. If you `npm install -g @earendil-works/pi-coding-agent` yourself, the user-installed copy on the volume wins via `PATH` order and survives image rebuilds.
|
||||
|
||||
### Configuration
|
||||
|
||||
The entrypoint copies `pi-toolkit/settings.example.json` to `~/.pi/agent/settings.json` on first start. Edit it to set provider/model:
|
||||
|
||||
```bash
|
||||
docker compose exec -u developer devbox $EDITOR ~/.pi/agent/settings.json
|
||||
```
|
||||
|
||||
The AWS env loader (`pi-env.zsh`) reads `~/.config/pi/.env` if you bind-mount one; otherwise pi uses container env vars passed via `.env`.
|
||||
|
||||
## AWS Bedrock Authentication
|
||||
|
||||
When using AWS Bedrock as your LLM provider, you need:
|
||||
|
||||
Reference in New Issue
Block a user