Compare commits

..

11 Commits

Author SHA1 Message Date
joakimp 2d9fadf220 Bump opencode to v1.4.7
Publish Docker Image / build-omos (push) Successful in 1h22m23s
Publish Docker Image / build-base (push) Successful in 1h33m12s
Publish Docker Image / update-description (push) Successful in 18s
2026-04-17 11:28:34 +02:00
joakimp f08480182a Bump opencode to v1.4.6
Publish Docker Image / build-omos (push) Successful in 1h19m28s
Publish Docker Image / build-base (push) Successful in 1h30m47s
Publish Docker Image / update-description (push) Successful in 13s
2026-04-15 12:21:29 +02:00
joakimp 5ec47fdf4b Add AGENTS.md with project-specific guidance for opencode sessions 2026-04-14 19:28:26 +02:00
joakimp 210cb7d1a1 Document Python 3.13 included by default in Trixie base image 2026-04-14 13:01:49 +02:00
joakimp 0a3e142b8f Document locale and editor override in README and DOCKER_HUB 2026-04-14 08:37:08 +02:00
joakimp 158e1590a6 Generate all UTF-8 locales, allow locale override via env vars
Users can set LANG, LANGUAGE, LC_ALL in .env to override the default
en_US.UTF-8 locale (e.g. sv_SE.UTF-8 for Swedish).
2026-04-14 08:35:42 +02:00
joakimp 271dc2eb35 Fix Bedrock config: add AWS_PROFILE to generated config, add .agents/skills to volume ownership fix
Publish Docker Image / build-omos (push) Successful in 36m41s
Publish Docker Image / build-base (push) Successful in 38m37s
Publish Docker Image / update-description (push) Successful in 17s
2026-04-13 19:52:08 +02:00
joakimp 875afe0039 Add ~/.local/bin and ~/.cargo/bin to PATH for uv and rustup 2026-04-13 19:48:31 +02:00
joakimp 9e381ebe32 Fix ownership of named volume mount points in entrypoint
Named Docker volumes are created as root on first use, causing permission
denied errors for the developer user. The entrypoint now fixes ownership
of all known volume mount points after UID/GID adjustment.
2026-04-13 19:46:25 +02:00
joakimp 3e048218c3 Update Python example from 3.12 to 3.14 (current stable) 2026-04-13 19:14:33 +02:00
joakimp 6ecd65d18d Update Bedrock model example to eu.anthropic.claude-opus-4-6-v1 2026-04-13 19:04:21 +02:00
7 changed files with 116 additions and 14 deletions
+5
View File
@@ -31,6 +31,11 @@ WORKSPACE_PATH=~/projects
# Path to SSH keys on host
SSH_KEY_PATH=~/.ssh
# ── Locale (defaults to en_US.UTF-8) ─────────────────────────────────
# LANG=sv_SE.UTF-8
# LANGUAGE=sv_SE:sv
# LC_ALL=sv_SE.UTF-8
# ── oh-my-opencode-slim (multi-agent orchestration) ──────────────────
# Requires image built with INSTALL_OMOS=true
# ENABLE_OMOS=false
+47
View File
@@ -0,0 +1,47 @@
# AGENTS.md
## Project overview
Docker image packaging [opencode](https://opencode.ai) 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.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 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)`
+28 -6
View File
@@ -114,6 +114,25 @@ The entrypoint automatically detects the owner of `/workspace` and adjusts the c
| `USER_UID` | Container user UID | Auto-detect from `/workspace` owner |
| `USER_GID` | Container user GID | Auto-detect from `/workspace` owner |
### Locale and Editor
The container defaults to English (`en_US.UTF-8`) and neovim as the editor. Override via environment variables:
| Variable | Description | Default |
|---|---|---|
| `LANG` | System locale | `en_US.UTF-8` |
| `LANGUAGE` | Language priority list | `en_US:en` |
| `LC_ALL` | Override all locale settings | `en_US.UTF-8` |
| `EDITOR` | Default text editor | `nvim` |
All common UTF-8 locales are pre-generated in the image. Example for Swedish:
```bash
LANG=sv_SE.UTF-8
LANGUAGE=sv_SE:sv
LC_ALL=sv_SE.UTF-8
```
## Initial Setup
### 1. Create host directories
@@ -157,7 +176,7 @@ GIT_USER_EMAIL=you@example.com
**AWS Bedrock (SSO):**
```bash
OPENCODE_PROVIDER=amazon-bedrock
OPENCODE_MODEL=amazon-bedrock/anthropic.claude-sonnet-4-5-v1
OPENCODE_MODEL=amazon-bedrock/eu.anthropic.claude-opus-4-6-v1
AWS_REGION=eu-west-1
AWS_PROFILE=your-profile-name
GIT_USER_NAME=Your Name
@@ -237,13 +256,13 @@ docker run -it --rm \
## Python Development with uv
The image includes [uv](https://docs.astral.sh/uv/), a fast Python package manager that replaces pip, venv, and pyenv. Python is not pre-installed but can be installed on demand:
The image includes Python 3.13 (from Debian Trixie) and [uv](https://docs.astral.sh/uv/), a fast Python package manager that replaces pip, venv, and pyenv:
```bash
# Install Python (persists across restarts with devbox-uv volume)
uv python install 3.12
# Python 3.13 is available out of the box
python3 --version
# Create a virtual environment and install dependencies
# Use uv for package management
uv venv
uv pip install -r requirements.txt
@@ -255,6 +274,9 @@ uv run python script.py
# Install standalone Python tools
uvx ruff check .
# Install a newer Python version (persists with devbox-uv volume)
uv python install 3.14
```
To persist Python installs across container restarts, add a named volume:
@@ -352,7 +374,7 @@ mkdir opencode-devbox && cd opencode-devbox
```bash
OPENCODE_PROVIDER=amazon-bedrock
OPENCODE_MODEL=amazon-bedrock/anthropic.claude-sonnet-4-5-v1
OPENCODE_MODEL=amazon-bedrock/eu.anthropic.claude-opus-4-6-v1
AWS_REGION=eu-west-1
AWS_PROFILE=your-profile-name
GIT_USER_NAME=Your Name
+4 -3
View File
@@ -5,7 +5,7 @@ ARG DEBIAN_VERSION=trixie-slim
FROM debian:${DEBIAN_VERSION} AS base
ARG TARGETARCH
ARG OPENCODE_VERSION=1.4.3
ARG OPENCODE_VERSION=1.4.7
LABEL maintainer="joakimp"
LABEL description="Portable opencode developer container"
@@ -107,12 +107,13 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64"
curl -fsSL "https://static.rust-lang.org/rustup/dist/${ARCH}-unknown-linux-gnu/rustup-init" -o /usr/local/bin/rustup-init && \
chmod +x /usr/local/bin/rustup-init
# Set locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
# Set locale — generate common UTF-8 locales (override via LANG/LC_ALL env vars)
RUN sed -i '/\.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
ENV EDITOR=nvim
ENV PATH="/home/developer/.local/bin:/home/developer/.cargo/bin:${PATH}"
# ── Node.js (required for opencode v1.x install + MCP servers) ──────
ARG NODE_VERSION=22
+11 -4
View File
@@ -117,6 +117,10 @@ docker compose exec -u developer devbox aws --version
| `SSH_KEY_PATH` | Host SSH key directory | `~/.ssh` |
| `USER_UID` | Override container user UID | Auto-detect from `/workspace` |
| `USER_GID` | Override container user GID | Auto-detect from `/workspace` |
| `LANG` | System locale | `en_US.UTF-8` |
| `LANGUAGE` | Language priority list | `en_US:en` |
| `LC_ALL` | Override all locale settings | `en_US.UTF-8` |
| `EDITOR` | Default text editor | `nvim` |
| `ENABLE_OMOS` | Enable oh-my-opencode-slim multi-agent orchestration | `false` |
| `OMOS_TMUX` | Enable tmux pane integration for OMOS | `false` |
| `OMOS_SKILLS` | Install OMOS recommended skills on first run | `true` |
@@ -153,13 +157,13 @@ volumes:
### Python development with uv
The image includes [uv](https://docs.astral.sh/uv/), a fast Python package manager that replaces pip, venv, and pyenv. Python is not pre-installed but can be installed on demand:
The image includes Python 3.13 (from Debian Trixie) and [uv](https://docs.astral.sh/uv/), a fast Python package manager that replaces pip, venv, and pyenv:
```bash
# Install Python (persists across restarts with devbox-uv volume)
uv python install 3.12
# Python 3.13 is available out of the box
python3 --version
# Create a virtual environment and install dependencies
# Use uv for package management
uv venv
uv pip install -r requirements.txt
@@ -171,6 +175,9 @@ uv run python script.py
# Install standalone Python tools
uvx ruff check .
# Install a newer Python version (persists with devbox-uv volume)
uv python install 3.14
```
Python installations are stored in `~/.local/share/uv/`. To persist them across container restarts, add the `devbox-uv` named volume to your `docker-compose.yml`:
+2 -1
View File
@@ -48,7 +48,8 @@ EOF
"provider": {
"amazon-bedrock": {
"options": {
"region": "${AWS_REGION:-us-east-1}"
"region": "${AWS_REGION:-us-east-1}",
"profile": "${AWS_PROFILE:-default}"
}
}
}
+19
View File
@@ -46,5 +46,24 @@ if [ -d "/home/$USER_NAME/.ssh" ] && [ "$(ls -A "/home/$USER_NAME/.ssh" 2>/dev/n
fi
fi
# ── Fix ownership of named volume mount points ──────────────────────
# Named volumes are created as root on first use. Fix ownership so the
# developer user can write to them.
FINAL_UID="${TARGET_UID:-$CURRENT_UID}"
FINAL_GID="${TARGET_GID:-$CURRENT_GID}"
for dir in \
/home/"$USER_NAME"/.local/share/opencode \
/home/"$USER_NAME"/.local/share/uv \
/home/"$USER_NAME"/.rustup \
/home/"$USER_NAME"/.cargo \
/home/"$USER_NAME"/.vscode-server \
/home/"$USER_NAME"/.config/opencode \
/home/"$USER_NAME"/.config/nvim \
/home/"$USER_NAME"/.agents/skills; do
if [ -d "$dir" ] && [ "$(stat -c '%u' "$dir" 2>/dev/null)" != "$FINAL_UID" ]; then
chown -R "$FINAL_UID":"$FINAL_GID" "$dir" 2>/dev/null || true
fi
done
# ── Drop to developer user for remaining setup ──────────────────────
exec gosu "$USER_NAME" /usr/local/bin/entrypoint-user.sh "$@"