diff --git a/.gitea/README.md b/.gitea/README.md index 4c45c95..366bdee 100644 --- a/.gitea/README.md +++ b/.gitea/README.md @@ -13,7 +13,7 @@ the build pipeline is shaped the way it is, you're in the right place. ## Why the split-base pipeline exists -opencode-devbox publishes **five image variants** (`base`, `omos`, `with-pi`, `omos-with-pi`, `pi-only`) × **two architectures** (amd64, arm64) = **ten image tags per release**. Today's runners are 2 self-hosted gitea Actions runners. arm64 builds are emulated under QEMU, which is the dominant cost (~3–5x slower than native). +opencode-devbox builds **five image variants** (`base`, `omos`, `with-pi`, `omos-with-pi`, `pi-only`) × **two architectures** (amd64, arm64). Four opencode-bearing variants publish under this repo (**eight tags per release** + the floating `base-latest`); the `pi-only` build is pushed into the separate `joakimp/pi-devbox` repo as `base-pi-only` (so no opencode-less tag appears here). Today's runners are 2 self-hosted gitea Actions runners. arm64 builds are emulated under QEMU, which is the dominant cost (~3–5x slower than native). The five variants share ~95% of their layers (Debian + apt + Node + AWS CLI + mempalace + dev tools + entrypoints). The original `Dockerfile` was a single multi-stage build with `INSTALL_*` build-args gating variant-specific RUNs. BuildKit's per-layer cache key is content-addressed, but as soon as a build-arg-gated `RUN` produces a different layer hash for variant A vs variant B, every subsequent layer also has a different parent → identical commands re-execute per variant. Result: minimal cross-variant cache reuse on a fresh build. diff --git a/.gitea/workflows/docker-publish-split.yml b/.gitea/workflows/docker-publish-split.yml index 8d330fa..ae97cb1 100644 --- a/.gitea/workflows/docker-publish-split.yml +++ b/.gitea/workflows/docker-publish-split.yml @@ -37,6 +37,11 @@ concurrency: env: BUILDKIT_PROGRESS: plain IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/opencode-devbox + # The pi-only variant is built here (single source of truth for the pi stack) + # but published into the pi-devbox repo as an internal building-block tag, + # NOT under opencode-devbox — so opencode-devbox never shows a tag with no + # opencode in it. pi-devbox's own CI FROMs PI_IMAGE:base-pi-only. + PI_IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/pi-devbox RELEASE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || inputs.release_tag }} PROMOTE_LATEST: ${{ github.ref_type == 'tag' && 'true' || inputs.promote_latest }} @@ -801,11 +806,14 @@ jobs: - name: Compute version-specific tags id: tags run: | + # Option B: push the pi-only build into the pi-devbox repo as an + # internal building-block tag (base-pi-only[-]), NOT under + # opencode-devbox. pi-devbox's CI FROMs ${PI_IMAGE}:base-pi-only. VERSION="${{ env.RELEASE_TAG }}" { echo "tags<> "$GITHUB_OUTPUT" diff --git a/AGENTS.md b/AGENTS.md index e39b14b..2660dc5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ Docker image packaging [opencode](https://opencode.ai) into a production-ready d ## File roles - `Dockerfile.base` — variant-independent layers (apt, locales, AWS CLI, Node.js, mempalace, gitea-mcp, user setup, chromadb prewarm, ENVs, entrypoints). Published as `joakimp/opencode-devbox:base-`. Rebuilt only when its content hash changes. -- `Dockerfile.variant` — `FROM`s the base and adds only opencode/omos/pi installs gated by build args: `INSTALL_OPENCODE` (default true), `INSTALL_OMOS`, `INSTALL_PI`, and `INSTALL_MEMPALACE`. All GitHub-sourced binaries are pinned with version ARGs. When `INSTALL_PI=true` it also clones `pi-fork` + `pi-observational-memory` (from `github.com/elpapi42`, refs `PI_FORK_REF`/`PI_OBSMEM_REF`) to `/opt` and runs `npm install` there at build time so the `fork`/`recall` extensions can load (a local-path `pi install` does not npm-install). The `pi-only` variant sets `INSTALL_OPENCODE=false`, `INSTALL_PI=true` — pi without opencode, the single source of truth for the separate `pi-devbox` image. +- `Dockerfile.variant` — `FROM`s the base and adds only opencode/omos/pi installs gated by build args: `INSTALL_OPENCODE` (default true), `INSTALL_OMOS`, `INSTALL_PI`, and `INSTALL_MEMPALACE`. All GitHub-sourced binaries are pinned with version ARGs. When `INSTALL_PI=true` it also clones `pi-fork` + `pi-observational-memory` (from `github.com/elpapi42`, refs `PI_FORK_REF`/`PI_OBSMEM_REF`) to `/opt` and runs `npm install` there at build time so the `fork`/`recall` extensions can load (a local-path `pi install` does not npm-install). The `pi-only` variant sets `INSTALL_OPENCODE=false`, `INSTALL_PI=true` — pi without opencode, the single source of truth for the separate `pi-devbox` image. It is built and smoke-tested here, but **published into the `joakimp/pi-devbox` repo** as the internal building-block tag `base-pi-only[-vX.Y.Z]` (NOT under `opencode-devbox`), so an opencode-devbox tag never ships without opencode. - `entrypoint.sh` — runs as root: UID/GID adjustment, SSH permissions, volume ownership fixes (skipped via `.devbox-owner` sentinel when ownership is already correct). Then drops to developer via gosu. Volume ownership loop covers `~/.pi/` when `INSTALL_PI=true`. - `entrypoint-user.sh` — runs as developer: git config, opencode.jsonc generation (delegated to `generate-config.py`), LAN-access setup (delegated to `setup-lan-access.sh`), pi-toolkit + pi-extensions deploy (when pi installed), pi settings.json bootstrap, mempalace pi-bridge symlink, runtime `pi install /opt/{pi-fork,pi-observational-memory}` registration (idempotent), skillset auto-deploy from mounted skillset repo, OMOS setup. - `rootfs/usr/local/lib/opencode-devbox/setup-lan-access.sh` — host-OS-agnostic LAN reachability helper. Detects VM-backed hosts (macOS OrbStack / Docker Desktop, via `host.docker.internal` resolution) and generates a writable `~/.ssh-local/config` using the host as an SSH jump; no-op on native Linux. Controlled by `DEVBOX_LAN_ACCESS` / `HOST_SSH_USER` / `DEVBOX_HOST_ALIAS`. Ships the mechanism only (generic `host` jump alias); user targets stay in their bind-mounted `~/.ssh/config`. Non-fatal. Counted in the base hash, so editing it advances `base-latest`. @@ -36,7 +36,7 @@ Tags follow `v{opencode_version}[letter]` — e.g. `v1.14.20` for the first buil Cautionary example: 2026-05-28 morning, `v1.15.12` was cut while opencode-ai was still at `1.15.11`. The commit message itself acknowledged "OPENCODE_VERSION stays at 1.15.11" but tagged `v1.15.12` anyway. Re-cut as `v1.15.11c` the same afternoon (see CHANGELOG). The `v1.15.12` git tag and Hub images stayed as historical artifacts; the slip cost a CI cycle and a CHANGELOG-rewrite. **Run the npm view check at the top of every release-day cut.** -CI produces ten Docker Hub tags per release: `vX.Y.Z[n]`, `latest`, `vX.Y.Z[n]-omos`, `latest-omos`, `vX.Y.Z[n]-with-pi`, `latest-with-pi`, `vX.Y.Z[n]-omos-with-pi`, `latest-omos-with-pi`, `vX.Y.Z[n]-pi-only`, `latest-pi-only` — one tag pair (versioned + floating alias) per build variant (five variants). +CI produces eight Docker Hub tags **under `opencode-devbox`** per release: `vX.Y.Z[n]`, `latest`, `vX.Y.Z[n]-omos`, `latest-omos`, `vX.Y.Z[n]-with-pi`, `latest-with-pi`, `vX.Y.Z[n]-omos-with-pi`, `latest-omos-with-pi` — one tag pair (versioned + floating alias) per opencode-bearing variant (four variants). A fifth build, `pi-only`, is built+smoked here but pushed into the **`joakimp/pi-devbox`** repo as `base-pi-only-vX.Y.Z` (+ `base-pi-only` on tag builds), where it becomes the base for that image. When bumping the opencode version, bump `OPENCODE_VERSION` in `Dockerfile.variant` and update the comment in `.env.example` if it names a specific model/version for context. diff --git a/CHANGELOG.md b/CHANGELOG.md index a4dc0e2..54f2f11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,23 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a ## Unreleased -_(no changes since v1.15.13b)_ +### Changed: `pi-only` build now publishes to the `joakimp/pi-devbox` repo (not `opencode-devbox`) + +The `pi-only` variant (added in v1.15.13b) was published under `opencode-devbox` +as `latest-pi-only` / `vX.Y.Z-pi-only` — an "opencode-devbox" tag that contains +**no opencode**, which confused users browsing the tag list. + +- The `build-variant-pi-only` CI job now pushes the artifact into the + **`joakimp/pi-devbox`** repo as `base-pi-only-vX.Y.Z` (+ floating `base-pi-only` + on tag builds) instead of `opencode-devbox:*-pi-only`. New `PI_IMAGE` workflow env. +- It is still built from the same `Dockerfile.variant` (single source of truth) + and still smoke-tested by `smoke-pi-only` / `validate-pi-only` before publish. +- `opencode-devbox` now publishes **eight** tags per release (four opencode-bearing + variants) plus `base-latest`; the pi-only pair lives in the pi-devbox repo. +- De-advertised the pi-only tag from the README, `DOCKER_HUB.md` (HUB_TEMPLATE), + and AGENTS docs. +- The old `opencode-devbox:latest-pi-only` / `vX.Y.Z-pi-only` tags from v1.15.13b + are superseded and should be deleted from Docker Hub. ## v1.15.13b — 2026-06-03 diff --git a/DOCKER_HUB.md b/DOCKER_HUB.md index cc083a0..5953511 100644 --- a/DOCKER_HUB.md +++ b/DOCKER_HUB.md @@ -12,10 +12,14 @@ Designed for teams who want a reproducible coding-agent setup that runs the same | `latest-omos` / `vX.Y.Z-omos` | Base + [oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim) multi-agent orchestration and Bun | | `latest-with-pi` / `vX.Y.Z-with-pi` | Base + [pi](https://github.com/earendil-works/pi) as alternative/complementary harness (shares the mempalace install with opencode) | | `latest-omos-with-pi` / `vX.Y.Z-omos-with-pi` | OMOS + pi together | -| `latest-pi-only` / `vX.Y.Z-pi-only` | pi without opencode — the lean, pi-focused variant (basis of the separate `joakimp/pi-devbox` image) | All variants support `linux/amd64` and `linux/arm64`. +> A fifth, pi-without-opencode build is produced from the same `Dockerfile.variant` +> (`INSTALL_OPENCODE=false`) but is **not** published under this repo — it ships as +> the separate [`joakimp/pi-devbox`](https://hub.docker.com/r/joakimp/pi-devbox) +> image so an "opencode-devbox" tag never lacks opencode. + ## Quick Start For a fully-configured environment with persistent state (opencode config, mempalace memory, neovim plugins, bash history) surviving container recreation, use docker-compose. **You don't need to clone the repo** — just grab two template files: diff --git a/README.md b/README.md index 6bbed48..9452326 100644 --- a/README.md +++ b/README.md @@ -463,7 +463,7 @@ All six agents should respond if your provider authentication is working. ### 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. There is also a `latest-pi-only` variant (pi **without** opencode, `INSTALL_OPENCODE=false`) — it's the lean basis for the separate [`joakimp/pi-devbox`](https://gitea.jordbo.se/joakimp/pi-devbox) image. Alternatively, build from source: +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 diff --git a/docs/plan-lan-access-and-pi-extensions.md b/docs/plan-lan-access-and-pi-extensions.md index e99f9c1..455790e 100644 --- a/docs/plan-lan-access-and-pi-extensions.md +++ b/docs/plan-lan-access-and-pi-extensions.md @@ -127,6 +127,16 @@ image so pi-install logic (incl. the new fork/obsmem clones) lives in ONE place. > (`INSTALL_OPENCODE=false`, `INSTALL_PI=true`) was added to opencode-devbox, and > pi-devbox now `FROM`s `latest-pi-only`. Same single-source-of-truth win, but > pi-devbox stays lean (no opencode, ~145 MB lighter than with-pi). +> +> **Update 2 (2026-06-03, Option B):** publishing the pi-only variant as +> `opencode-devbox:latest-pi-only` meant an "opencode-devbox" Hub tag that +> contains no opencode — confusing. Final scheme: the pi-only build is still +> produced by opencode-devbox CI (single source of truth) but its +> `build-variant-pi-only` job pushes into the **`joakimp/pi-devbox`** repo as +> the internal building-block tag `base-pi-only` (+ `base-pi-only-vX.Y.Z`), and +> pi-devbox now `FROM`s `joakimp/pi-devbox:base-pi-only`. No opencode-less tag +> ever appears under opencode-devbox; pi-only is de-advertised from +> opencode-devbox's README/DOCKER_HUB. New `PI_IMAGE` workflow env. ### Build time — clone to /opt + npm install (mirror pi-toolkit/extensions pattern) Add to the single `INSTALL_PI=true` block in `opencode-devbox/Dockerfile.variant` diff --git a/scripts/generate-dockerhub-md.py b/scripts/generate-dockerhub-md.py index 33703ae..619fde0 100755 --- a/scripts/generate-dockerhub-md.py +++ b/scripts/generate-dockerhub-md.py @@ -66,10 +66,14 @@ Designed for teams who want a reproducible coding-agent setup that runs the same | `latest-omos` / `vX.Y.Z-omos` | Base + [oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim) multi-agent orchestration and Bun | | `latest-with-pi` / `vX.Y.Z-with-pi` | Base + [pi](https://github.com/earendil-works/pi) as alternative/complementary harness (shares the mempalace install with opencode) | | `latest-omos-with-pi` / `vX.Y.Z-omos-with-pi` | OMOS + pi together | -| `latest-pi-only` / `vX.Y.Z-pi-only` | pi without opencode — the lean, pi-focused variant (basis of the separate `joakimp/pi-devbox` image) | All variants support `linux/amd64` and `linux/arm64`. +> A fifth, pi-without-opencode build is produced from the same `Dockerfile.variant` +> (`INSTALL_OPENCODE=false`) but is **not** published under this repo — it ships as +> the separate [`joakimp/pi-devbox`](https://hub.docker.com/r/joakimp/pi-devbox) +> image so an "opencode-devbox" tag never lacks opencode. + ## Quick Start For a fully-configured environment with persistent state (opencode config, mempalace memory, neovim plugins, bash history) surviving container recreation, use docker-compose. **You don't need to clone the repo** — just grab two template files: