3.6 KiB
3.6 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 byINSTALL_OMOS=truebuild 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.4.3k. The number matches the opencode npm version. The letter suffix increments for container-level changes (tooling, docs, CVE fixes) on the same opencode version. CI produces four Docker Hub tags per release: vX.Y.Zn, latest, vX.Y.Zn-omos, latest-omos.
Critical conventions
- entrypoint.sh volume ownership loop — when adding a new named volume mount point, add it to the
for dir in ...loop inentrypoint.shso 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 sourcedocker-compose.ymlpattern. - 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
ARCHcase-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/tokenendpoint (not the deprecated/v2/users/login). Auth usesidentifier/secretfields, returnsaccess_token, sent asBearer. Short description must be ≤100 bytes.
CI quirks
- Both build jobs include an IPv4 preference step (
gai.conf+driver-opts: network=hostfor buildx) to work around intermittent IPv6 failures on the Gitea runners. update-descriptionjob runs only when both builds succeed (needs: [build-base, build-omos]).- Tags must be pushed to trigger CI. Pushing to
mainalone does not build images.
Testing changes
No test suite. Verify by:
- Building locally:
docker compose build - Running:
docker compose run --rm devbox bash - Checking tool availability inside container:
nvim --version,bat --version,uv --version, etc. - 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 entrypointAdd uv package manager to base image for on-demand Python supportUpgrade base image from Debian bookworm to trixie (current stable)