Add INSTALL_PI build arg for pi as second harness
Optional integration of pi-coding-agent alongside opencode in the same
container. Both harnesses share the mempalace install and palace path —
wing/diary entries are mutually visible.
Build:
--build-arg INSTALL_PI=true # opt-in
--build-arg PI_VERSION=0.73.1 # pin a version (default: latest)
--build-arg INSTALL_OPENCODE=false # build pi-only image
Dockerfile:
• New INSTALL_PI block: npm install -g @mariozechner/pi-coding-agent
+ git-clones pi-toolkit and pi-extensions to /opt/.
• Existing opencode install gated behind new INSTALL_OPENCODE arg
(default true; existing builds unaffected).
• mkdir adds ~/.pi/agent/extensions for the named volume mount root.
• CMD changed from ['opencode'] to ['bash', '-l']. compose run --rm
devbox now drops to a login shell so users pick the harness; pass
'opencode' or 'pi' explicitly to launch directly. compose exec
workflows are unaffected (bypass entrypoint+CMD).
entrypoint.sh:
• Adds ~/.pi to volume ownership loop.
entrypoint-user.sh:
• New 'pi: deploy toolkit + extensions + mempalace bridge' block runs
pi-toolkit/install.sh, pi-extensions/install.sh, settings.json
template bootstrap, then symlinks the mempalace.ts bridge directly.
Order: toolkit before extensions before bridge. mempalace-toolkit's
full install.sh is intentionally NOT called (its install_skill
would race with skillset auto-deploy --prune-stale).
docker-compose.yml:
• New devbox-pi-config named volume mounted at /home/developer/.pi.
Persists user toggles (/ext-disabled extensions) and settings.json
edits across container recreate. Mirrors devbox-opencode-config
pattern from v1.14.33.
scripts/smoke-test.sh:
• New --variant with-pi (threshold 2700 MB) and --variant omos-with-pi
(3400 MB).
• Pi assertions gated on `command -v pi`: version, /opt/pi-toolkit
clone HEAD, /opt/pi-extensions clone HEAD, deployed keybindings
symlink, ≥4 extension symlinks, mempalace.ts bridge symlink,
settings.json bootstrap.
• Pi state assertions use docker exec from the host (not 'run'),
since the container has no docker CLI.
• opencode core test now gated on INSTALL_OPENCODE presence.
scripts/generate-dockerhub-md.py:
• SECTION_RULES adds 'pi (alternative/complementary harness)': drop.
Section stays in README; dropped from DOCKER_HUB.md to keep under
the 25 kB Docker Hub limit.
Docs:
• README adds full 'pi (alternative/complementary harness)' section.
• AGENTS.md codifies pi install contract, deploy ordering, named
volume rationale, and CMD change.
• CHANGELOG.md gets an Unreleased entry.
• .env.example documents new build args.
• docker-compose.yml example args block updated.
Verification (local builds on arm64):
• Default (INSTALL_PI=false): 1871 MB, all assertions pass — no
regression.
• INSTALL_PI=true: 2110 MB (within 2700 threshold), 37 assertions
pass including pi version, all 7 extensions deployed (6 from
pi-extensions + mempalace.ts bridge), settings.json bootstrap.
Not yet:
• CI workflow updates to add -with-pi tag variants. Deferred until
local path stabilizes through user testing.
• pi-devbox separate repo for fully stripped pi-only image. Phase 2.
This commit is contained in:
+59
-4
@@ -271,9 +271,50 @@ RUN curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors https://deb.nodesour
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ── Install opencode via npm ─────────────────────────────────────────
|
||||
# v1.x is distributed as an npm package with platform-specific binaries
|
||||
RUN npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
||||
opencode --version
|
||||
# v1.x is distributed as an npm package with platform-specific binaries.
|
||||
# Disable with --build-arg INSTALL_OPENCODE=false to build a slimmer
|
||||
# image without opencode (e.g. when only pi is needed). For a fully
|
||||
# pi-only stripped image (no Bun, no opencode), see the pi-devbox repo.
|
||||
ARG INSTALL_OPENCODE=true
|
||||
RUN if [ "${INSTALL_OPENCODE}" = "true" ]; then \
|
||||
npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
||||
opencode --version ; \
|
||||
fi
|
||||
|
||||
# ── Optional: pi coding-agent ────────────────────────────────────────
|
||||
# Installs pi as an alternative/complementary harness. Coexists with
|
||||
# opencode in the same image — both share the mempalace install and
|
||||
# palace path, so wing data is mutually visible to either harness.
|
||||
#
|
||||
# pi-toolkit (keybindings.json + pi-env.zsh + settings.example.json)
|
||||
# and pi-extensions (confirm-destructive, ext-toggle, git-checkpoint,
|
||||
# notify, ssh-controlmaster, todo, …) are cloned into /opt/ at build
|
||||
# time. entrypoint-user.sh runs each repo's install.sh on container
|
||||
# start so symlinks land under ~/.pi/agent/ on the named volume.
|
||||
#
|
||||
# Pi version is pinned by PI_VERSION (default: latest at build time).
|
||||
# `pi update` inside the container would write to the npm global
|
||||
# prefix, which is not on a volume — so updates do NOT persist across
|
||||
# `--rm` containers. Same contract as OPENCODE_VERSION: rebuild the
|
||||
# image to upgrade pi.
|
||||
ARG INSTALL_PI=false
|
||||
ARG PI_VERSION=latest
|
||||
ARG PI_TOOLKIT_REF=main
|
||||
ARG PI_EXTENSIONS_REF=main
|
||||
RUN if [ "${INSTALL_PI}" = "true" ]; then \
|
||||
if [ "${PI_VERSION}" = "latest" ]; then \
|
||||
npm install -g @mariozechner/pi-coding-agent ; \
|
||||
else \
|
||||
npm install -g @mariozechner/pi-coding-agent@${PI_VERSION} ; \
|
||||
fi && \
|
||||
pi --version && \
|
||||
git clone --depth 1 --branch "${PI_TOOLKIT_REF}" \
|
||||
https://gitea.jordbo.se/joakimp/pi-toolkit.git /opt/pi-toolkit && \
|
||||
git clone --depth 1 --branch "${PI_EXTENSIONS_REF}" \
|
||||
https://gitea.jordbo.se/joakimp/pi-extensions.git /opt/pi-extensions && \
|
||||
echo "pi-toolkit at $(cd /opt/pi-toolkit && git rev-parse --short HEAD)" && \
|
||||
echo "pi-extensions at $(cd /opt/pi-extensions && git rev-parse --short HEAD)" ; \
|
||||
fi
|
||||
|
||||
# ── AWS CLI v2 (for SSO/Bedrock authentication) ─────────────────────
|
||||
RUN ARCH=$(case "${TARGETARCH}" in \
|
||||
@@ -342,8 +383,15 @@ RUN groupadd --gid ${USER_GID} ${USER_NAME} && \
|
||||
echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/${USER_NAME}
|
||||
|
||||
# Create standard directories
|
||||
#
|
||||
# ~/.pi/agent/extensions/ is created proactively so the named volume
|
||||
# mount has a real owner from the first start. The directory is also
|
||||
# what mempalace-toolkit's install_pi_extension probes to decide
|
||||
# whether to deploy the pi↔mempalace bridge — must exist before that
|
||||
# step runs in entrypoint-user.sh.
|
||||
RUN mkdir -p /workspace \
|
||||
/home/${USER_NAME}/.config/opencode/skills \
|
||||
/home/${USER_NAME}/.pi/agent/extensions \
|
||||
/home/${USER_NAME}/.agents/skills \
|
||||
/home/${USER_NAME}/.local/share/opencode \
|
||||
/home/${USER_NAME}/.cache/bash \
|
||||
@@ -374,4 +422,11 @@ RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/entrypoint-user.sh \
|
||||
WORKDIR /workspace
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
CMD ["opencode"]
|
||||
# Default to a login shell. `docker compose run --rm devbox` drops
|
||||
# the user into bash to choose: `aws sso login`, then `opencode`
|
||||
# or `pi`. To launch a harness directly, pass it explicitly:
|
||||
# docker compose run --rm devbox opencode
|
||||
# docker compose run --rm devbox pi
|
||||
# `docker compose exec` bypasses the entrypoint and CMD entirely, so
|
||||
# this default has no effect on attach-style workflows.
|
||||
CMD ["bash", "-l"]
|
||||
|
||||
Reference in New Issue
Block a user