Files
opencode-devbox/AGENTS.md
T
joakimp c851b4cc8d
Publish Docker Image / build-omos (push) Successful in 43m57s
Publish Docker Image / build-base (push) Successful in 45m46s
Publish Docker Image / update-description (push) Successful in 16s
Clarify tag-letter convention: suffix is build ordinal, 'a' is never used
Previous phrasing treated the letter suffix as a plain alphabetical
sequence, which led to confusion about whether the first rebuild
should be 'a' or 'b'. Spell out the intent: the suffix is the build
ordinal, and the letter 'a' is reserved to mean '1st build' — which
always uses the bare tag (no letter). So letters start at 'b' for
the 2nd build, 'c' for the 3rd, and so on.

Examples for opencode version 1.14.20:
  1st build: v1.14.20
  2nd build: v1.14.20b
  3rd build: v1.14.20c
2026-04-21 23:58:12 +02:00

4.5 KiB

AGENTS.md

Project overview

Docker image packaging opencode into a production-ready dev container. Two image variants (base and omos) are published to Docker Hub via Gitea Actions CI. Not a library or application — this is infrastructure (Dockerfile, entrypoint scripts, docker-compose, documentation).

File roles

  • Dockerfile — single multi-stage build for both variants. OMOS variant is controlled by INSTALL_OMOS=true build arg. All GitHub-sourced binaries are pinned with version ARGs.
  • entrypoint.sh — runs as root: UID/GID adjustment, SSH permissions, volume ownership fixes. Then drops to developer via gosu.
  • entrypoint-user.sh — runs as developer: git config, opencode.json generation from env vars, OMOS setup.
  • DOCKER_HUB.md — pushed to Docker Hub description via CI API call. Must stay under 25KB. Short description field must be ≤100 bytes.
  • README.md — source repo documentation. Must stay in sync with DOCKER_HUB.md (both describe the same features but for different audiences).
  • .gitea/workflows/docker-publish.yml — CI pipeline: three parallel jobs (build-base, build-omos, update-description). Triggered by tag push only.

Versioning scheme

Tags follow v{opencode_version}[letter] — e.g. v1.14.20 for the first build on a new opencode release, and v1.14.20b, v1.14.20c, … for subsequent rebuilds on the same opencode version.

  • The number tracks the opencode npm version (see OPENCODE_VERSION ARG in Dockerfile).
  • No letter suffix on the first build of a new opencode version — the bare v{opencode_version} tag is the canonical release.
  • Letter suffix is the build ordinal, starting at b for the second build. The letter a is never used — think of the suffix as counting rebuilds: b = 2nd, c = 3rd, d = 4th, …. For opencode version 1.14.20: first build v1.14.20, second v1.14.20b, third v1.14.20c, and so on.
  • A letter suffix is only used for container-level rebuilds — tooling changes, CVE fixes, doc-driven rebuilds, entrypoint bugfixes — that don't change the underlying opencode version.

CI produces four Docker Hub tags per release: vX.Y.Z[n], latest, vX.Y.Z[n]-omos, latest-omos.

When bumping the opencode version, also bump OPENCODE_VERSION in Dockerfile and update the comment in .env.example if it names a specific model/version for context.

Critical conventions

  • entrypoint.sh volume ownership loop — when adding a new named volume mount point, add it to the for dir in ... loop in entrypoint.sh so root-owned volumes get chowned on startup.
  • Three docs to keep in sync — Dockerfile changes that add tools or features must be reflected in README.md, DOCKER_HUB.md, and .env.example. The docker-compose examples in both docs must match the source docker-compose.yml pattern.
  • GitHub-sourced binaries — fzf, gosu, git-lfs, neovim, bat, eza, zoxide, uv, rustup are installed from upstream releases (not apt) with pinned versions. Use the same ARCH case-switch pattern for multi-arch support (amd64/arm64).
  • Shell scripts use set -euo pipefail — both entrypoints are strict. Errors in volume chown or SSH permission operations are intentionally suppressed with || true.
  • Docker Hub description update — uses /v2/auth/token endpoint (not the deprecated /v2/users/login). Auth uses identifier/secret fields, returns access_token, sent as Bearer. Short description must be ≤100 bytes.

CI quirks

  • Both build jobs include an IPv4 preference step (gai.conf + driver-opts: network=host for buildx) to work around intermittent IPv6 failures on the Gitea runners.
  • update-description job runs only when both builds succeed (needs: [build-base, build-omos]).
  • Tags must be pushed to trigger CI. Pushing to main alone does not build images.

Testing changes

No test suite. Verify by:

  1. Building locally: docker compose build
  2. Running: docker compose run --rm devbox bash
  3. Checking tool availability inside container: nvim --version, bat --version, uv --version, etc.
  4. For entrypoint changes: test with a non-1000 UID workspace to verify UID adjustment and volume ownership fixes.

Commit style

Imperative mood, first line summarizes the change. Multi-line body explains "why" when non-obvious. Examples from history:

  • Fix ownership of named volume mount points in entrypoint
  • Add uv package manager to base image for on-demand Python support
  • Upgrade base image from Debian bookworm to trixie (current stable)