Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad4a12b3ab | |||
| fde5a89e8b | |||
| 034830710c | |||
| d293ddc202 | |||
| 910378fe06 | |||
| f06a70a3bc | |||
| dba05da7d1 |
@@ -526,7 +526,7 @@ jobs:
|
|||||||
- build-variant-omos
|
- build-variant-omos
|
||||||
- build-variant-with-pi
|
- build-variant-with-pi
|
||||||
- build-variant-omos-with-pi
|
- build-variant-omos-with-pi
|
||||||
if: env.PROMOTE_LATEST == 'true'
|
if: ${{ github.ref_type == 'tag' || inputs.promote_latest == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: catthehacker/ubuntu:act-latest
|
image: catthehacker/ubuntu:act-latest
|
||||||
@@ -550,7 +550,7 @@ jobs:
|
|||||||
- build-variant-omos
|
- build-variant-omos
|
||||||
- build-variant-with-pi
|
- build-variant-with-pi
|
||||||
- build-variant-omos-with-pi
|
- build-variant-omos-with-pi
|
||||||
if: env.PROMOTE_LATEST == 'true'
|
if: ${{ github.ref_type == 'tag' || inputs.promote_latest == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: catthehacker/ubuntu:act-latest
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
|||||||
@@ -4,6 +4,22 @@ name: Validate
|
|||||||
# runs the smoke test, and checks image size — without pushing anything
|
# runs the smoke test, and checks image size — without pushing anything
|
||||||
# to Docker Hub. Tag pushes are handled by docker-publish-split.yml which
|
# to Docker Hub. Tag pushes are handled by docker-publish-split.yml which
|
||||||
# does the full multi-arch split-base build-and-push.
|
# does the full multi-arch split-base build-and-push.
|
||||||
|
#
|
||||||
|
# Trade-off: variant builds here use the published `base-latest` image
|
||||||
|
# from Docker Hub as their parent, NOT a locally-built base. This is
|
||||||
|
# because `docker/build-push-action@v7` runs each invocation in its own
|
||||||
|
# buildx container context, so an image loaded into the host docker
|
||||||
|
# daemon by step N is not visible to step N+1's buildx invocation.
|
||||||
|
# Building base + variant in the same job would require either pushing
|
||||||
|
# the base to a registry or sharing a buildx instance across steps — both
|
||||||
|
# significantly more complex than just using the published base.
|
||||||
|
#
|
||||||
|
# Consequence: PRs/pushes that change Dockerfile.base, rootfs/, or
|
||||||
|
# entrypoint*.sh are NOT exercised by this workflow. The release path
|
||||||
|
# (docker-publish-split.yml on tag push) does build the new base, so
|
||||||
|
# release tags are the gate that fully validates base-image changes.
|
||||||
|
# The base-change-warning job below surfaces a runtime warning when this
|
||||||
|
# blind-spot applies.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -34,6 +50,33 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python3 scripts/generate-dockerhub-md.py --check
|
python3 scripts/generate-dockerhub-md.py --check
|
||||||
|
|
||||||
|
base-change-warning:
|
||||||
|
# Surfaces a warning when this commit changes base-image inputs
|
||||||
|
# (Dockerfile.base, rootfs/, entrypoint*.sh). validate.yml uses
|
||||||
|
# Hub's base-latest as the parent for variant builds, so changes to
|
||||||
|
# those files are NOT exercised here — only release tags rebuild the
|
||||||
|
# base via docker-publish-split.yml.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Detect base-input changes
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
if ! git diff --name-only HEAD~1 HEAD 2>/dev/null \
|
||||||
|
| grep -qE '^(Dockerfile\.base|rootfs/|entrypoint.*\.sh)$'; then
|
||||||
|
echo "No base-image inputs changed in this commit — validate.yml fully exercises the published base-latest."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "::warning::This commit changes base-image inputs (Dockerfile.base, rootfs/, or entrypoint*.sh). validate.yml uses Hub's base-latest as the parent for variant builds, so the new base is NOT exercised by this workflow. Cut a release tag, or run a workflow_dispatch of docker-publish-split.yml against a test tag (e.g. v0.0.0-base-test, promote_latest=false) for end-to-end validation of the new base."
|
||||||
|
echo "Changed base-input files:"
|
||||||
|
git diff --name-only HEAD~1 HEAD | grep -E '^(Dockerfile\.base|rootfs/|entrypoint.*\.sh)$'
|
||||||
|
|
||||||
validate-base:
|
validate-base:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
@@ -79,16 +122,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
|
|
||||||
- name: Build base layer (amd64, load to local daemon)
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: Dockerfile.base
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: false
|
|
||||||
load: true
|
|
||||||
tags: opencode-devbox:validate-base
|
|
||||||
|
|
||||||
- name: Build base image (amd64, load to local daemon)
|
- name: Build base image (amd64, load to local daemon)
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -98,7 +131,7 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
load: true
|
load: true
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=opencode-devbox:validate-base
|
BASE_IMAGE=joakimp/opencode-devbox:base-latest
|
||||||
tags: opencode-devbox:ci-base
|
tags: opencode-devbox:ci-base
|
||||||
|
|
||||||
- name: Smoke test
|
- name: Smoke test
|
||||||
@@ -146,16 +179,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
|
|
||||||
- name: Build base layer (amd64, load to local daemon)
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: Dockerfile.base
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: false
|
|
||||||
load: true
|
|
||||||
tags: opencode-devbox:validate-base
|
|
||||||
|
|
||||||
- name: Build omos image (amd64, load to local daemon)
|
- name: Build omos image (amd64, load to local daemon)
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -165,7 +188,7 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
load: true
|
load: true
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=opencode-devbox:validate-base
|
BASE_IMAGE=joakimp/opencode-devbox:base-latest
|
||||||
INSTALL_OMOS=true
|
INSTALL_OMOS=true
|
||||||
tags: opencode-devbox:ci-omos
|
tags: opencode-devbox:ci-omos
|
||||||
|
|
||||||
@@ -214,16 +237,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
|
|
||||||
- name: Build base layer (amd64, load to local daemon)
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: Dockerfile.base
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: false
|
|
||||||
load: true
|
|
||||||
tags: opencode-devbox:validate-base
|
|
||||||
|
|
||||||
- name: Build with-pi image (amd64, load to local daemon)
|
- name: Build with-pi image (amd64, load to local daemon)
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -233,7 +246,7 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
load: true
|
load: true
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=opencode-devbox:validate-base
|
BASE_IMAGE=joakimp/opencode-devbox:base-latest
|
||||||
INSTALL_PI=true
|
INSTALL_PI=true
|
||||||
tags: opencode-devbox:ci-with-pi
|
tags: opencode-devbox:ci-with-pi
|
||||||
|
|
||||||
@@ -282,16 +295,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
|
|
||||||
- name: Build base layer (amd64, load to local daemon)
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: Dockerfile.base
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: false
|
|
||||||
load: true
|
|
||||||
tags: opencode-devbox:validate-base
|
|
||||||
|
|
||||||
- name: Build omos+with-pi image (amd64, load to local daemon)
|
- name: Build omos+with-pi image (amd64, load to local daemon)
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -301,7 +304,7 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
load: true
|
load: true
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=opencode-devbox:validate-base
|
BASE_IMAGE=joakimp/opencode-devbox:base-latest
|
||||||
INSTALL_OMOS=true
|
INSTALL_OMOS=true
|
||||||
INSTALL_PI=true
|
INSTALL_PI=true
|
||||||
tags: opencode-devbox:ci-omos-with-pi
|
tags: opencode-devbox:ci-omos-with-pi
|
||||||
|
|||||||
@@ -8,6 +8,55 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## v1.15.3 — 2026-05-16
|
||||||
|
|
||||||
|
opencode 1.15.0 → 1.15.3 bump (three upstream patch releases).
|
||||||
|
|
||||||
|
- **Bump:** opencode 1.15.0 → 1.15.3 (`OPENCODE_VERSION` in `Dockerfile.variant`).
|
||||||
|
- No container-side changes. Smoke thresholds from v1.15.0b unchanged.
|
||||||
|
|
||||||
|
## v1.15.0b — 2026-05-15
|
||||||
|
|
||||||
|
Rebuild of v1.15.0 with one fix — v1.15.0's `omos` variant landed at 3206 MB, 6 MB over the 3200 MB smoke threshold, so `smoke-omos` failed and `build-variant-omos` was skipped. opencode 1.15.0 grew slightly vs 1.14.50, leaving zero headroom on the existing threshold.
|
||||||
|
|
||||||
|
- **Smoke threshold bump:** `omos` 3200 → 3300 MB, `omos-with-pi` 3400 → 3500 MB. Restores ~100 MB headroom for routine apt-get upgrade drift between releases. Documented inline in `scripts/smoke-test.sh`. No image-side changes — cache hits across the board, just a re-publish on the bumped threshold.
|
||||||
|
|
||||||
|
## v1.15.0 — 2026-05-15
|
||||||
|
|
||||||
|
opencode 1.14.50 → 1.15.0 bump (upstream minor release).
|
||||||
|
|
||||||
|
- **Bump:** opencode 1.14.50 → 1.15.0 (`OPENCODE_VERSION` in `Dockerfile.variant`).
|
||||||
|
- **Resilience:** `git clone` for pi-toolkit and pi-extensions in `Dockerfile.variant` is now wrapped in a 5-attempt retry loop with linear backoff (5s, 10s, 15s, 20s, 25s = up to ~75s total). gitea.jordbo.se occasionally returns transient HTTP 500s on the first request after idle, which previously broke the with-pi and omos-with-pi variant builds. Same pattern landed in pi-devbox repo concurrently.
|
||||||
|
- **Docs:** `DOCKER_HUB.md` mentions `joakimp/pi-devbox` as a sibling image — the pi-only build that uses this image's base layer as its parent. Generator template (`scripts/generate-dockerhub-md.py`) updated and regenerated. Hub size: 5905 bytes (well under the 25 kB limit).
|
||||||
|
- **Recovery from v1.14.50c partial publish:** the `latest-omos`, `v1.14.50c-omos` Hub gap is closed by this release — `latest-omos` will move forward to v1.15.0 once all four variants publish cleanly. Users on the floating tag were unaffected (still pointing at v1.14.41b until now).
|
||||||
|
|
||||||
|
## v1.14.50c — 2026-05-14
|
||||||
|
|
||||||
|
Recovery release for v1.14.50b's missing variants. v1.14.50b shipped only the `base` variant; `omos`, `with-pi`, and `omos-with-pi` were lost to a runner-fleet incident (see postmortem below).
|
||||||
|
|
||||||
|
No container-side changes. This is a tag-only retag to re-run the build on a now-healthy runner fleet. Same `base-35ee5fe7861a` from v1.14.50b is reused via hash-cache hit; only the four variant deltas are rebuilt and published.
|
||||||
|
|
||||||
|
### Postmortem: v1.14.50 / v1.14.50b runner-fleet incident
|
||||||
|
|
||||||
|
Two orthogonal runner-host issues compounded across runs 285–291:
|
||||||
|
|
||||||
|
1. **AVX-less runner shadowing the new fleet.** A pre-migration `act_runner` container on `nyvaken` (Sandy Bridge E3-12xx, has AVX but no AVX2; 4 weeks old, name `act_runner-runner-1`) collided with the orchestrator's freshly deployed `runner-1` VM (Broadwell-EP host, fully AVX2-capable). Gitea scheduled jobs to both. Jobs landing on the nyvaken container `npm install -g opencode-ai@1.14.50` succeeded, then ran `opencode --version` postinstall → the bundled Bun (v1.3.13 baseline) emitted `CPU lacks AVX support`, panicked, and SIGILLed (exit code 132).
|
||||||
|
2. **Containerd shared-state race at `capacity: 2`.** The new VM-based runners initially ran `act_runner` with `capacity: 2`, scheduling two concurrent jobs on a single host. Both jobs would invoke `docker/setup-buildx-action@v4`, which pulls `moby/buildkit:buildx-stable-1`. Containerd's content store raced on identical sha256 ingestion, surfacing as `commit failed: rename .../ingest/.../data .../blobs/sha256/...: no such file or directory` or `failed to extract layer: failed to Lchown ...`.
|
||||||
|
|
||||||
|
A secondary issue surfaced: **Proxmox VM `cpu:` field defaults mask AVX**. The newly-cloned runner VMs had no explicit `cpu:` line in `qm config` and inherited Proxmox's recent default `x86-64-v2-AES`, which excludes AVX even though the Broadwell-EP host silicon has full `avx2`. Fix: `qm set <vmid> --cpu x86-64-v3` (or `host` for full passthrough), then `qm shutdown` + `qm start` (live reboot is not enough). Verified inside guest with `grep -m1 -oE 'avx[2]?' /proc/cpuinfo`.
|
||||||
|
|
||||||
|
Additionally, when `promote-base-latest`'s `needs:` graph requires *all four* `build-variant-*` jobs to succeed, partial publishes leave the `base-latest` Hub alias never advancing. Workaround used during recovery: manually re-tag the new base hash via Docker Hub registry manifest API (`PUT /v2/<repo>/manifests/base-latest` with the body of `GET /v2/<repo>/manifests/base-<sha>`) using a granular Hub PAT. No blob copy needed since blobs are content-addressed.
|
||||||
|
|
||||||
|
### Recovery actions taken (orchestrator + this repo)
|
||||||
|
|
||||||
|
- Orchestrator (cloud-init + ansible repos): set explicit `cpu_type: x86-64-v3` in all runner host yaml files; provision.sh now applies `qm set --cpu` after clone; added runner-3 on proxmox003 for anti-affinity (one runner per Proxmox node); dropped `capacity: 2 → 1` on all runners; bumped `act_runner` 0.3.1 → 0.6.1 across the fleet; documented the CPU-type gotcha as gotcha #9 in cloud-init AGENTS.md and a section in proxmox-guide.md.
|
||||||
|
- User: retired the legacy `act_runner-runner-1` container on nyvaken; cleaned up stale runner registrations in Gitea Site Admin → Actions → Runners.
|
||||||
|
- This repo: no changes needed in Dockerfile.base / Dockerfile.variant; v1.14.50c is a tag-only retag.
|
||||||
|
|
||||||
|
### Fleet state at v1.14.50c
|
||||||
|
|
||||||
|
3 runners (runner-1@proxmox001, runner-2@proxmox002, runner-3@proxmox003), all `act_runner` v0.6.1, all `capacity: 1`, all expose AVX + AVX2 to the guest. No name collisions. Estimated wall clock for v1.14.50c (cache-hit base, 4 variant deltas across 3 runners with capacity:1): ~40–50 min.
|
||||||
|
|
||||||
## v1.14.50b — 2026-05-14
|
## v1.14.50b — 2026-05-14
|
||||||
|
|
||||||
Rebuild of v1.14.50 with two fixes — the v1.14.50 release was incomplete (smokes failed under containerd contention; build-variant jobs skipped; base-latest never promoted to Docker Hub).
|
Rebuild of v1.14.50 with two fixes — the v1.14.50 release was incomplete (smokes failed under containerd contention; build-variant jobs skipped; base-latest never promoted to Docker Hub).
|
||||||
|
|||||||
+20
-16
@@ -17,6 +17,21 @@ All variants support `linux/amd64` and `linux/arm64`.
|
|||||||
|
|
||||||
## Quick Start
|
## 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/opencode-devbox && cd ~/opencode-devbox
|
||||||
|
curl -O https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml
|
||||||
|
curl -fsSL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env
|
||||||
|
# Edit .env — set OPENCODE_PROVIDER, the matching API key,
|
||||||
|
# WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL.
|
||||||
|
docker compose run --rm devbox
|
||||||
|
```
|
||||||
|
|
||||||
|
This drops you straight into opencode with your project mounted at `/workspace`. Use `bash` as the command (e.g. `docker compose run --rm devbox bash`) to land in a shell first — useful for `aws sso login`, `pi` (on `*-with-pi` variants), or multi-harness workflows.
|
||||||
|
|
||||||
|
**One-shot run, no persistence:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm \
|
docker run -it --rm \
|
||||||
-e ANTHROPIC_API_KEY=your-key \
|
-e ANTHROPIC_API_KEY=your-key \
|
||||||
@@ -28,22 +43,7 @@ docker run -it --rm \
|
|||||||
joakimp/opencode-devbox:latest
|
joakimp/opencode-devbox:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Drops you straight into opencode with your project mounted at `/workspace`.
|
Full setup guide — authentication for each provider (Anthropic, OpenAI, Bedrock SSO + static), persistence model, build args, troubleshooting: <https://gitea.jordbo.se/joakimp/opencode-devbox#readme>
|
||||||
|
|
||||||
For an interactive shell first (useful for AWS SSO login, multi-harness workflows, or just `bash`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -it --rm \
|
|
||||||
-e ANTHROPIC_API_KEY=your-key \
|
|
||||||
-e OPENCODE_PROVIDER=anthropic \
|
|
||||||
-v ~/projects:/workspace \
|
|
||||||
-v ~/.ssh:/home/developer/.ssh:ro \
|
|
||||||
joakimp/opencode-devbox:latest bash
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run `opencode`, `pi` (on `*-with-pi` variants), or `aws sso login` from the shell.
|
|
||||||
|
|
||||||
For docker-compose users, the source repo provides `docker-compose.yml`, `.env.example`, and a one-liner `docker compose up -d` workflow with named volumes pre-wired.
|
|
||||||
|
|
||||||
## What's Inside
|
## What's Inside
|
||||||
|
|
||||||
@@ -86,6 +86,10 @@ Full persistence reference, including multi-user (`SIGNUM`) isolation and host b
|
|||||||
- **Issues / source / docker-compose templates:** <https://gitea.jordbo.se/joakimp/opencode-devbox>
|
- **Issues / source / docker-compose templates:** <https://gitea.jordbo.se/joakimp/opencode-devbox>
|
||||||
- **Agent-facing internals** (for future maintainers / coding agents working in the repo): <https://gitea.jordbo.se/joakimp/opencode-devbox/src/branch/main/AGENTS.md>
|
- **Agent-facing internals** (for future maintainers / coding agents working in the repo): <https://gitea.jordbo.se/joakimp/opencode-devbox/src/branch/main/AGENTS.md>
|
||||||
|
|
||||||
|
## Sibling images
|
||||||
|
|
||||||
|
- **[`joakimp/pi-devbox`](https://hub.docker.com/r/joakimp/pi-devbox)** — pi-only image built on top of this image's base layer. Smaller (~700 MB) and version-tracks the [pi npm package](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) directly. Use this if you want pi without opencode. Source: <https://gitea.jordbo.se/joakimp/pi-devbox>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT. See <https://gitea.jordbo.se/joakimp/opencode-devbox/src/branch/main/LICENSE>.
|
MIT. See <https://gitea.jordbo.se/joakimp/opencode-devbox/src/branch/main/LICENSE>.
|
||||||
|
|||||||
+14
-5
@@ -32,7 +32,7 @@ ARG USER_NAME=developer
|
|||||||
|
|
||||||
# ── Install opencode via npm ─────────────────────────────────────────
|
# ── Install opencode via npm ─────────────────────────────────────────
|
||||||
ARG INSTALL_OPENCODE=true
|
ARG INSTALL_OPENCODE=true
|
||||||
ARG OPENCODE_VERSION=1.14.50
|
ARG OPENCODE_VERSION=1.15.3
|
||||||
RUN if [ "${INSTALL_OPENCODE}" = "true" ]; then \
|
RUN if [ "${INSTALL_OPENCODE}" = "true" ]; then \
|
||||||
NPM_CONFIG_PREFIX=/usr npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
NPM_CONFIG_PREFIX=/usr npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
||||||
opencode --version ; \
|
opencode --version ; \
|
||||||
@@ -47,16 +47,25 @@ ARG PI_VERSION=latest
|
|||||||
ARG PI_TOOLKIT_REF=main
|
ARG PI_TOOLKIT_REF=main
|
||||||
ARG PI_EXTENSIONS_REF=main
|
ARG PI_EXTENSIONS_REF=main
|
||||||
RUN if [ "${INSTALL_PI}" = "true" ]; then \
|
RUN if [ "${INSTALL_PI}" = "true" ]; then \
|
||||||
|
set -e && \
|
||||||
|
git_clone_retry() { \
|
||||||
|
url="$1"; ref="$2"; dest="$3"; \
|
||||||
|
for i in 1 2 3 4 5; do \
|
||||||
|
if git clone --depth 1 --branch "$ref" "$url" "$dest"; then return 0; fi; \
|
||||||
|
rm -rf "$dest"; \
|
||||||
|
echo "git clone $url failed (attempt $i/5), retrying in $((i*5))s..."; \
|
||||||
|
sleep $((i*5)); \
|
||||||
|
done; \
|
||||||
|
return 1; \
|
||||||
|
} && \
|
||||||
if [ "${PI_VERSION}" = "latest" ]; then \
|
if [ "${PI_VERSION}" = "latest" ]; then \
|
||||||
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent ; \
|
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent ; \
|
||||||
else \
|
else \
|
||||||
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent@${PI_VERSION} ; \
|
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent@${PI_VERSION} ; \
|
||||||
fi && \
|
fi && \
|
||||||
pi --version && \
|
pi --version && \
|
||||||
git clone --depth 1 --branch "${PI_TOOLKIT_REF}" \
|
git_clone_retry https://gitea.jordbo.se/joakimp/pi-toolkit.git "${PI_TOOLKIT_REF}" /opt/pi-toolkit && \
|
||||||
https://gitea.jordbo.se/joakimp/pi-toolkit.git /opt/pi-toolkit && \
|
git_clone_retry https://gitea.jordbo.se/joakimp/pi-extensions.git "${PI_EXTENSIONS_REF}" /opt/pi-extensions && \
|
||||||
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-toolkit at $(cd /opt/pi-toolkit && git rev-parse --short HEAD)" && \
|
||||||
echo "pi-extensions at $(cd /opt/pi-extensions && git rev-parse --short HEAD)" ; \
|
echo "pi-extensions at $(cd /opt/pi-extensions && git rev-parse --short HEAD)" ; \
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -8,8 +8,28 @@ The official `ghcr.io/anomalyco/opencode` image (now archived) was Alpine-based
|
|||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
**Just want to run it?** No git clone needed — grab the two template files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/opencode-devbox && cd ~/opencode-devbox
|
||||||
|
|
||||||
|
# Pull docker-compose.yml and the .env template
|
||||||
|
curl -O https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml
|
||||||
|
curl -fsSL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env
|
||||||
|
|
||||||
|
# Edit .env — at minimum: OPENCODE_PROVIDER, the matching API key,
|
||||||
|
# WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL.
|
||||||
|
$EDITOR .env
|
||||||
|
|
||||||
|
# Pull and run
|
||||||
|
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.
|
||||||
|
|
||||||
|
**Want to hack on the image itself, follow upstream changes, or rebuild from source?** Clone the repo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone
|
|
||||||
git clone ssh://gitea.jordbo.se:2222/joakimp/opencode-devbox.git
|
git clone ssh://gitea.jordbo.se:2222/joakimp/opencode-devbox.git
|
||||||
cd opencode-devbox
|
cd opencode-devbox
|
||||||
|
|
||||||
@@ -17,7 +37,7 @@ cd opencode-devbox
|
|||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# Edit .env with your provider, API key, workspace path, git config
|
# Edit .env with your provider, API key, workspace path, git config
|
||||||
|
|
||||||
# Install git hooks (secret scanning)
|
# Install git hooks (secret scanning) before committing
|
||||||
brew install gitleaks # macOS / Linuxbrew
|
brew install gitleaks # macOS / Linuxbrew
|
||||||
./setup-hooks.sh
|
./setup-hooks.sh
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,21 @@ All variants support `linux/amd64` and `linux/arm64`.
|
|||||||
|
|
||||||
## Quick Start
|
## 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/opencode-devbox && cd ~/opencode-devbox
|
||||||
|
curl -O https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/docker-compose.yml
|
||||||
|
curl -fsSL https://gitea.jordbo.se/joakimp/opencode-devbox/raw/branch/main/.env.example -o .env
|
||||||
|
# Edit .env — set OPENCODE_PROVIDER, the matching API key,
|
||||||
|
# WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL.
|
||||||
|
docker compose run --rm devbox
|
||||||
|
```
|
||||||
|
|
||||||
|
This drops you straight into opencode with your project mounted at `/workspace`. Use `bash` as the command (e.g. `docker compose run --rm devbox bash`) to land in a shell first — useful for `aws sso login`, `pi` (on `*-with-pi` variants), or multi-harness workflows.
|
||||||
|
|
||||||
|
**One-shot run, no persistence:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm \\
|
docker run -it --rm \\
|
||||||
-e ANTHROPIC_API_KEY=your-key \\
|
-e ANTHROPIC_API_KEY=your-key \\
|
||||||
@@ -82,22 +97,7 @@ docker run -it --rm \\
|
|||||||
joakimp/opencode-devbox:latest
|
joakimp/opencode-devbox:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Drops you straight into opencode with your project mounted at `/workspace`.
|
Full setup guide — authentication for each provider (Anthropic, OpenAI, Bedrock SSO + static), persistence model, build args, troubleshooting: <{GITEA}#readme>
|
||||||
|
|
||||||
For an interactive shell first (useful for AWS SSO login, multi-harness workflows, or just `bash`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -it --rm \\
|
|
||||||
-e ANTHROPIC_API_KEY=your-key \\
|
|
||||||
-e OPENCODE_PROVIDER=anthropic \\
|
|
||||||
-v ~/projects:/workspace \\
|
|
||||||
-v ~/.ssh:/home/developer/.ssh:ro \\
|
|
||||||
joakimp/opencode-devbox:latest bash
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run `opencode`, `pi` (on `*-with-pi` variants), or `aws sso login` from the shell.
|
|
||||||
|
|
||||||
For docker-compose users, the source repo provides `docker-compose.yml`, `.env.example`, and a one-liner `docker compose up -d` workflow with named volumes pre-wired.
|
|
||||||
|
|
||||||
## What's Inside
|
## What's Inside
|
||||||
|
|
||||||
@@ -140,6 +140,10 @@ Full persistence reference, including multi-user (`SIGNUM`) isolation and host b
|
|||||||
- **Issues / source / docker-compose templates:** <{GITEA}>
|
- **Issues / source / docker-compose templates:** <{GITEA}>
|
||||||
- **Agent-facing internals** (for future maintainers / coding agents working in the repo): <{GITEA}/src/branch/main/AGENTS.md>
|
- **Agent-facing internals** (for future maintainers / coding agents working in the repo): <{GITEA}/src/branch/main/AGENTS.md>
|
||||||
|
|
||||||
|
## Sibling images
|
||||||
|
|
||||||
|
- **[`joakimp/pi-devbox`](https://hub.docker.com/r/joakimp/pi-devbox)** — pi-only image built on top of this image's base layer. Smaller (~700 MB) and version-tracks the [pi npm package](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) directly. Use this if you want pi without opencode. Source: <https://gitea.jordbo.se/joakimp/pi-devbox>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT. See <{GITEA}/src/branch/main/LICENSE>.
|
MIT. See <{GITEA}/src/branch/main/LICENSE>.
|
||||||
|
|||||||
@@ -289,14 +289,16 @@ SIZE_BYTES=$(docker image inspect --format='{{.Size}}' "$IMAGE")
|
|||||||
SIZE_MB=$((SIZE_BYTES / 1024 / 1024))
|
SIZE_MB=$((SIZE_BYTES / 1024 / 1024))
|
||||||
echo " Uncompressed size: ${SIZE_MB} MB"
|
echo " Uncompressed size: ${SIZE_MB} MB"
|
||||||
|
|
||||||
# Thresholds (uncompressed): base 2500 MB, omos 3200 MB, with-pi adds ~150 MB.
|
# Thresholds (uncompressed): base 2500 MB, omos 3300 MB, with-pi adds ~150 MB.
|
||||||
# omos bumped 3000→3200 on v1.14.31c — mempalace-toolkit bake-in pushed the
|
# omos bumped 3000→3200 on v1.14.31c — mempalace-toolkit bake-in pushed the
|
||||||
|
# baseline; bumped 3200→3300 on v1.15.0 — opencode 1.15.0 came in at
|
||||||
|
# 3206 MB, leaving zero headroom for routine apt-get upgrade drift.
|
||||||
# omos variant to ~3.1 GB. Functional smoke checks all pass; this is a
|
# omos variant to ~3.1 GB. Functional smoke checks all pass; this is a
|
||||||
# guardrail, not a performance limit.
|
# guardrail, not a performance limit.
|
||||||
THRESHOLD=2500
|
THRESHOLD=2500
|
||||||
[ "$VARIANT" = "omos" ] && THRESHOLD=3200
|
[ "$VARIANT" = "omos" ] && THRESHOLD=3300
|
||||||
[ "$VARIANT" = "with-pi" ] && THRESHOLD=2700
|
[ "$VARIANT" = "with-pi" ] && THRESHOLD=2700
|
||||||
[ "$VARIANT" = "omos-with-pi" ] && THRESHOLD=3400
|
[ "$VARIANT" = "omos-with-pi" ] && THRESHOLD=3500
|
||||||
if [ "$SIZE_MB" -gt "$THRESHOLD" ]; then
|
if [ "$SIZE_MB" -gt "$THRESHOLD" ]; then
|
||||||
fail "image size ${SIZE_MB} MB exceeds threshold ${THRESHOLD} MB for variant=$VARIANT"
|
fail "image size ${SIZE_MB} MB exceeds threshold ${THRESHOLD} MB for variant=$VARIANT"
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user