Compare commits

..

6 Commits

Author SHA1 Message Date
joakimp 8f2c9f5112 v1.15.4b: omos-with-pi threshold bump + update-description partial-publish fix
Validate / docs-check (push) Successful in 7s
Validate / base-change-warning (push) Successful in 20s
Validate / validate-base (push) Successful in 3m36s
Publish Docker Image / base-decide (push) Successful in 13s
Publish Docker Image / build-base (push) Has been skipped
Validate / validate-with-pi (push) Successful in 4m14s
Validate / validate-omos (push) Successful in 7m1s
Publish Docker Image / smoke-base (push) Successful in 3m37s
Publish Docker Image / smoke-omos (push) Successful in 4m39s
Publish Docker Image / smoke-omos-with-pi (push) Successful in 5m7s
Publish Docker Image / smoke-with-pi (push) Successful in 6m24s
Validate / validate-omos-with-pi (push) Successful in 15m59s
Publish Docker Image / build-variant-base (push) Successful in 14m12s
Publish Docker Image / build-variant-omos (push) Successful in 19m29s
Publish Docker Image / build-variant-with-pi (push) Successful in 23m7s
Publish Docker Image / build-variant-omos-with-pi (push) Successful in 26m16s
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Successful in 8s
Recovery for v1.15.4's partial publish (omos-with-pi exceeded 3500 MB
smoke threshold; other 3 variants published cleanly). Two changes:

1. omos-with-pi threshold 3500 -> 3700 MB. Compounded growth from
   opencode 1.15.0 -> 1.15.4 (4 patch versions) plus pi 0.74.0 -> 0.75.3
   (minor + 3 patches) summed in the omos-with-pi variant, just over
   the existing limit. Same pattern as prior threshold bumps (v1.14.31c,
   v1.15.0b). Restores ~150 MB headroom for routine apt-upgrade drift.

2. update-description workflow bug fix. Pre-existing latent bug exposed
   by v1.15.4's partial publish: update-description.needs includes all 4
   build-variant-* jobs, and gitea Actions' default behavior is
   'skipped need => skip dependent' \u2014 even when the job's own if:
   condition is satisfied. So when build-variant-omos-with-pi was
   skipped (because its smoke failed), update-description cascaded into
   a skip too, and Hub description didn't refresh on v1.15.4 despite
   3 variants publishing.

   Fix: wrap if: in always() + explicit success check on the base
   variant. Same fix applied to promote-base-latest preemptively (it
   has the same latent bug, currently masked by the cache-hit gate).

No image-side changes \u2014 cache hit on base-35ee5fe7861a.
2026-05-18 22:30:59 +02:00
joakimp 60eb49469e v1.15.4: bump opencode 1.15.3 -> 1.15.4
Publish Docker Image / base-decide (push) Successful in 14s
Validate / docs-check (push) Successful in 8s
Validate / base-change-warning (push) Successful in 7s
Validate / validate-base (push) Successful in 3m30s
Publish Docker Image / build-base (push) Has been skipped
Validate / validate-with-pi (push) Successful in 4m12s
Validate / validate-omos (push) Successful in 7m8s
Validate / validate-omos-with-pi (push) Successful in 5m7s
Publish Docker Image / smoke-omos (push) Successful in 4m23s
Publish Docker Image / smoke-base (push) Successful in 8m17s
Publish Docker Image / smoke-with-pi (push) Successful in 6m24s
Publish Docker Image / smoke-omos-with-pi (push) Failing after 11m14s
Publish Docker Image / build-variant-base (push) Successful in 14m38s
Publish Docker Image / build-variant-omos-with-pi (push) Has been skipped
Publish Docker Image / build-variant-omos (push) Successful in 19m40s
Publish Docker Image / build-variant-with-pi (push) Successful in 19m49s
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
Bundles with the CI hardening landed on main since v1.15.3 (T14/T15 in
the operator backlog):

- Pinned crane install in promote-base-latest (replaces flaky
  imjasonh/setup-crane@v0.4 that depends on api.github.com/releases/latest
  at runtime and periodically rate-limits)
- Skip promote-base-latest on cache-hit base builds (need_build='false')

These will be exercised on this release run \u2014 if the base hash hasn't
drifted since v1.15.3 (likely cache hit), promote-base-latest should
SKIP rather than RUN, and update-description picks up the new tag.
2026-05-18 21:51:15 +02:00
joakimp 18b9c9c549 CI: harden promote-base-latest (pinned crane + skip on cache-hit)
Validate / docs-check (push) Successful in 10s
Validate / base-change-warning (push) Successful in 16s
Validate / validate-with-pi (push) Successful in 4m10s
Validate / validate-omos (push) Successful in 4m34s
Validate / validate-base (push) Has been cancelled
Validate / validate-omos-with-pi (push) Has been cancelled
Two workflow-only changes for promote-base-latest, no image-side impact:

T14 \u2014 replace imjasonh/setup-crane@v0.4 with direct pinned crane install.
The action's bootstrap script calls api.github.com/.../releases/latest
at every run to discover the crane version. That call periodically
rate-limits and returns JSON without .tag_name, jq emits 'null', the
action then downloads .../releases/download/null/... \u2192 404 \u2192 'gzip:
unexpected end of file' \u2192 exit 2. We hit this on the v1.15.3 release
(2026-05-16) where it was cosmetic only \u2014 base-latest was already
correct from cache hit \u2014 but the red-X is annoying.

Replaced with curl + tar pinned to crane v0.21.6 (latest at time of
change). Same pattern as other GitHub-sourced binaries in the
Dockerfile layer (gosu, fzf, eza etc.); operator bumps CRANE_VERSION
deliberately when wanting updates.

T15 \u2014 gate promote-base-latest on need_build == 'true'. When the base
layer's content hash hasn't changed (cache hit on existing base-<hash>
from a prior run), base-latest already points at the correct digest.
The retag is a tautology, and any transient failure of it produces a
red-X for an operation that didn't need to happen. Skipping the job
entirely on cache-hit is correct and removes a whole class of cosmetic
failure. Manual workflow_dispatch with promote_latest=true still bypasses
the gate as an escape hatch (e.g., if base-latest got hand-deleted and
needs regeneration without rebuilding the base).

This will not trigger a CI publish run (main-branch commit, no tag).
2026-05-18 21:45:10 +02:00
joakimp ad4a12b3ab v1.15.3: bump opencode 1.15.0 -> 1.15.3
Validate / base-change-warning (push) Successful in 10s
Validate / docs-check (push) Successful in 17s
Validate / validate-omos (push) Successful in 4m29s
Validate / validate-with-pi (push) Successful in 4m17s
Validate / validate-omos-with-pi (push) Successful in 8m13s
Validate / validate-base (push) Successful in 8m48s
Publish Docker Image / base-decide (push) Successful in 12s
Publish Docker Image / promote-base-latest (push) Failing after 6s
Publish Docker Image / build-base (push) Has been cancelled
Publish Docker Image / smoke-base (push) Has been cancelled
Publish Docker Image / smoke-omos (push) Has been cancelled
Publish Docker Image / smoke-with-pi (push) Has been cancelled
Publish Docker Image / smoke-omos-with-pi (push) Has been cancelled
Publish Docker Image / build-variant-base (push) Has been cancelled
Publish Docker Image / build-variant-omos (push) Has been cancelled
Publish Docker Image / build-variant-with-pi (push) Has been cancelled
Publish Docker Image / build-variant-omos-with-pi (push) Has been cancelled
Publish Docker Image / update-description (push) Has been cancelled
2026-05-16 19:54:15 +02:00
joakimp fde5a89e8b README + DOCKER_HUB: lead with no-git-clone curl-template path
Validate / base-change-warning (push) Successful in 27s
Validate / docs-check (push) Successful in 39s
Validate / validate-omos (push) Successful in 4m39s
Validate / validate-with-pi (push) Successful in 4m14s
Validate / validate-omos-with-pi (push) Successful in 8m7s
Validate / validate-base (push) Successful in 9m50s
The previous Quick Start in both surfaces led with 'git clone',
which is overkill for users who just want to run the published image.
Match pi-devbox's pattern: lead with 'mkdir; curl docker-compose.yml;
curl .env.example; edit .env; docker compose run --rm devbox'. Keep
the git-clone path as 'for hackers/forkers'.

Required pre-step: make the gitea repo public so unauthenticated
curl to the raw URL works (done out of band — repo was private until
this commit landed).
2026-05-15 18:02:37 +02:00
joakimp 034830710c workflow: use github.ref_type directly in promote/update-description if-conditions
Validate / docs-check (push) Successful in 8s
Validate / base-change-warning (push) Successful in 10s
Validate / validate-with-pi (push) Successful in 4m23s
Validate / validate-omos-with-pi (push) Successful in 5m10s
Validate / validate-omos (push) Successful in 7m5s
Validate / validate-base (push) Successful in 10m5s
Gitea Actions evaluates 'env.PROMOTE_LATEST' as empty in YAML 'if:'
contexts even though the same env var substitutes correctly in
shell run: blocks. Result: on v1.15.0/v1.15.0b tag pushes, the
build-variant-* jobs correctly pushed latest-* aliases (shell context),
but promote-base-latest and update-description got skipped (YAML
context), so the Hub README description wasn't refreshed.

Switch to evaluating github.ref_type directly in the if-conditions —
matches the production-trigger semantics and avoids the env-var
indirection that gitea evaluates inconsistently.
2026-05-15 13:50:46 +02:00
7 changed files with 126 additions and 39 deletions
+41 -3
View File
@@ -526,12 +526,40 @@ jobs:
- build-variant-omos
- build-variant-with-pi
- build-variant-omos-with-pi
if: env.PROMOTE_LATEST == 'true'
# Skip on cache-hit base builds: when need_build=false, base-latest
# already points at the same digest as base-<hash>, so the retag is
# a tautology and any transient failure of it is purely cosmetic.
# Manual workflow_dispatch with promote_latest=true overrides this
# gate as an escape hatch (e.g., if base-latest got hand-deleted).
#
# `always()` wrapper + explicit base-variant success check protects
# against the gitea-Actions default of "skipped need => skip dependent":
# a partial-publish run (e.g., omos-with-pi smoke fails) shouldn't
# prevent the base-latest alias from advancing on a real base rebuild.
if: |
always() &&
needs.build-variant-base.result == 'success' &&
(inputs.promote_latest == 'true' ||
(github.ref_type == 'tag' && needs.base-decide.outputs.need_build == 'true'))
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- uses: imjasonh/setup-crane@v0.4
# Direct pinned install instead of imjasonh/setup-crane@v0.4. The
# action's bootstrap script calls api.github.com/.../releases/latest
# to discover the crane version, which periodically rate-limits and
# produces tag=null → download from .../download/null/... → 404 →
# 'gzip: unexpected end of file' → exit 2. Pinning removes the
# runtime dependency on GitHub API entirely. Bump CRANE_VERSION
# deliberately when you want updates.
- name: Install crane (pinned)
env:
CRANE_VERSION: v0.21.6
run: |
set -eux
curl -fsSL "https://github.com/google/go-containerregistry/releases/download/${CRANE_VERSION}/go-containerregistry_Linux_x86_64.tar.gz" \
| tar -xz -C /usr/local/bin crane
crane version
- name: Login (crane)
run: |
crane auth login docker.io \
@@ -550,7 +578,17 @@ jobs:
- build-variant-omos
- build-variant-with-pi
- build-variant-omos-with-pi
if: env.PROMOTE_LATEST == 'true'
# Run when at least the base variant published — don't let a single
# variant failure (e.g., omos-with-pi smoke threshold) prevent Hub
# description refresh for the other variants that did publish.
# Without this `always()` wrapper, gitea Actions' default behavior
# of "skipped need => skip dependent" cascades from any failed/
# skipped build-variant-* into update-description, and the Hub
# description goes stale on partial-publish releases.
if: |
always() &&
needs.build-variant-base.result == 'success' &&
(github.ref_type == 'tag' || inputs.promote_latest == 'true')
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
+25
View File
@@ -8,6 +8,31 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a
## Unreleased
## v1.15.4b — 2026-05-18
Recovery release for v1.15.4 — the `omos-with-pi` variant landed at >3500 MB and tripped the smoke threshold, so `smoke-omos-with-pi` and `build-variant-omos-with-pi` were skipped. The other three variants (base, omos, with-pi) published cleanly. Plus a latent workflow bug fix exposed by the partial publish.
- **Smoke threshold bump:** `omos-with-pi` 3500 → 3700 MB. Compounded growth: opencode 1.15.0 → 1.15.4 (4 patch versions) plus pi 0.74.0 → 0.75.3 (minor + 3 patches) both added a few MB each, and they sum in the omos-with-pi variant. Same pattern as previous threshold bumps (v1.14.31c, v1.15.0b); restores ~150 MB headroom.
- **Workflow fix — `update-description` no longer skips on partial publish.** Pre-existing latent bug: `update-description.needs` includes all four `build-variant-*` jobs, and gitea Actions' default behavior is "skipped need ⇒ skip dependent". When `build-variant-omos-with-pi` got skipped (because its smoke failed), `update-description` cascaded into a skip even though the job's `if:` condition (`tag pushed`) was true. Result: Hub description wasn't refreshed on v1.15.4 despite three variants publishing. Fix: wrap the `if:` in `always() && needs.build-variant-base.result == 'success' && ...` so the job runs as long as the base variant published, regardless of what other variants did.
- **Same fix applied to `promote-base-latest`** — had the identical latent bug. Currently masked by the cache-hit skip, but would have surfaced on a real-base-rebuild release with a single failed variant.
- No image-side changes from v1.15.4. Cache hit on the same base hash (`base-35ee5fe7861a`).
## v1.15.4 — 2026-05-18
opencode 1.15.3 → 1.15.4 bump (one upstream patch release), bundled with the CI hardening that landed on main between v1.15.3 and now.
- **Bump:** opencode 1.15.3 → 1.15.4 (`OPENCODE_VERSION` in `Dockerfile.variant`).
- **CI: pinned crane install in `promote-base-latest`.** Replaced `imjasonh/setup-crane@v0.4` with a direct `curl + tar` install pinned to crane v0.21.6. The action's bootstrap script calls `api.github.com/.../releases/latest` to discover what crane version to install. That call periodically rate-limits and produces `tag=null` → the action downloads `releases/download/null/...` → 404 → `gzip: unexpected end of file` → exit 2. We hit this on v1.15.3 (cosmetic failure since base-latest was already correct from cache hit). Pinned install removes the runtime GitHub API dependency entirely. Bump `CRANE_VERSION` deliberately when wanting updates, same pattern as the other GitHub-sourced binaries in the Dockerfile layer.
- **CI: skip `promote-base-latest` on cache-hit base builds.** When the base layer hash hasn't changed (cache-hit on the existing `base-<hash>` from a previous run), `base-latest` already points at the correct digest, so the retag is a tautology. Job now skipped entirely when `needs.base-decide.outputs.need_build == 'false'`. Manual `workflow_dispatch` with `promote_latest: true` overrides the gate as an escape hatch for hand-recovery scenarios.
- No image-side changes from the v1.15.3 baseline beyond the opencode npm version. Smoke thresholds unchanged.
## 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.
+16 -16
View File
@@ -17,6 +17,21 @@ All variants support `linux/amd64` and `linux/arm64`.
## 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
docker run -it --rm \
-e ANTHROPIC_API_KEY=your-key \
@@ -28,22 +43,7 @@ docker run -it --rm \
joakimp/opencode-devbox:latest
```
Drops you straight into opencode with your project mounted at `/workspace`.
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.
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>
## What's Inside
+1 -1
View File
@@ -32,7 +32,7 @@ ARG USER_NAME=developer
# ── Install opencode via npm ─────────────────────────────────────────
ARG INSTALL_OPENCODE=true
ARG OPENCODE_VERSION=1.15.0
ARG OPENCODE_VERSION=1.15.4
RUN if [ "${INSTALL_OPENCODE}" = "true" ]; then \
NPM_CONFIG_PREFIX=/usr npm install -g opencode-ai@${OPENCODE_VERSION} && \
opencode --version ; \
+22 -2
View File
@@ -8,8 +8,28 @@ The official `ghcr.io/anomalyco/opencode` image (now archived) was Alpine-based
## 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
# Clone
git clone ssh://gitea.jordbo.se:2222/joakimp/opencode-devbox.git
cd opencode-devbox
@@ -17,7 +37,7 @@ cd opencode-devbox
cp .env.example .env
# 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
./setup-hooks.sh
+16 -16
View File
@@ -71,6 +71,21 @@ All variants support `linux/amd64` and `linux/arm64`.
## 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
docker run -it --rm \\
-e ANTHROPIC_API_KEY=your-key \\
@@ -82,22 +97,7 @@ docker run -it --rm \\
joakimp/opencode-devbox:latest
```
Drops you straight into opencode with your project mounted at `/workspace`.
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.
Full setup guide — authentication for each provider (Anthropic, OpenAI, Bedrock SSO + static), persistence model, build args, troubleshooting: <{GITEA}#readme>
## What's Inside
+5 -1
View File
@@ -293,12 +293,16 @@ echo " Uncompressed size: ${SIZE_MB} MB"
# 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-with-pi bumped 3400→3500 on v1.15.0 alongside the omos bump.
# omos-with-pi bumped 3500→3700 on v1.15.4b — omos+pi compounded as both
# upstream packages grew (opencode 1.15.0→1.15.4, pi 0.74.0→0.75.3) and
# the variant landed just over 3500 in v1.15.4's smoke.
# omos variant to ~3.1 GB. Functional smoke checks all pass; this is a
# guardrail, not a performance limit.
THRESHOLD=2500
[ "$VARIANT" = "omos" ] && THRESHOLD=3300
[ "$VARIANT" = "with-pi" ] && THRESHOLD=2700
[ "$VARIANT" = "omos-with-pi" ] && THRESHOLD=3500
[ "$VARIANT" = "omos-with-pi" ] && THRESHOLD=3700
if [ "$SIZE_MB" -gt "$THRESHOLD" ]; then
fail "image size ${SIZE_MB} MB exceeds threshold ${THRESHOLD} MB for variant=$VARIANT"
else