Compare commits

...

7 Commits

Author SHA1 Message Date
joakimp b164c1b2f9 Bump opencode to v1.4.12
Publish Docker Image / build-omos (push) Successful in 42m1s
Publish Docker Image / build-base (push) Successful in 42m19s
Publish Docker Image / update-description (push) Successful in 14s
2026-04-18 23:11:46 +02:00
joakimp c59c66087a Limit locales to 16 common languages, document how to add more
Reduces locale generation from 200+ to 16 targeted locales (major world
languages + Nordic + key European). Saves build time and image size.
Users can add more at runtime via locale-gen.
2026-04-18 23:10:23 +02:00
joakimp e679fa06e6 Add check-versions.sh to compare pinned versions against latest releases
Run before tagging a release to see what tools have newer versions.
Reports only — does not modify files. Human decides what to bump.
2026-04-18 16:50:01 +02:00
joakimp d90dd76a46 Bump bat 0.26.1, uv 0.11.7, Go 1.26.2 2026-04-18 16:47:15 +02:00
joakimp 2153aa5659 Bump opencode to v1.4.11
Publish Docker Image / build-base (push) Successful in 1h15m31s
Publish Docker Image / build-omos (push) Failing after 1h29m23s
Publish Docker Image / update-description (push) Has been skipped
2026-04-18 16:43:38 +02:00
joakimp 0e4525ca53 Add git-crypt and age to base image for encrypted repo support 2026-04-18 16:40:52 +02:00
joakimp 43cecab0f7 Add shared-machine multi-user setup with per-user isolation via SIGNUM
For machines where multiple users share one OS account. Each user gets
isolated containers, config, and named volumes by running docker compose
from their own directory with a unique SIGNUM in .env.
2026-04-17 13:53:51 +02:00
6 changed files with 198 additions and 8 deletions
+27
View File
@@ -0,0 +1,27 @@
# ── Shared machine setup ─────────────────────────────────────────────
# Your corporate signum / username (REQUIRED)
# This isolates your container, config, and data from other users.
SIGNUM=your-signum-here
# ── Provider ─────────────────────────────────────────────────────────
OPENCODE_PROVIDER=amazon-bedrock
OPENCODE_MODEL=amazon-bedrock/eu.anthropic.claude-opus-4-6-v1
AWS_REGION=eu-west-1
AWS_PROFILE=default
# ── Git ──────────────────────────────────────────────────────────────
GIT_USER_NAME=Your Name
GIT_USER_EMAIL=your.name@example.com
# ── Paths (adjust to your layout) ───────────────────────────────────
# Default: ~/src mounted as /workspace
# WORKSPACE_PATH=~/src
# SSH keys — defaults to shared ~/.ssh
# If you have per-user keys: SSH_KEY_PATH=~/<signum>/.ssh
# 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
+13 -2
View File
@@ -125,7 +125,9 @@ The container defaults to English (`en_US.UTF-8`) and neovim as the editor. Over
| `LC_ALL` | Override all locale settings | `en_US.UTF-8` | | `LC_ALL` | Override all locale settings | `en_US.UTF-8` |
| `EDITOR` | Default text editor | `nvim` | | `EDITOR` | Default text editor | `nvim` |
All common UTF-8 locales are pre-generated in the image. Example for Swedish: Pre-generated locales: `en_US`, `en_GB`, `sv_SE`, `da_DK`, `nb_NO`, `fi_FI`, `de_DE`, `fr_FR`, `es_ES`, `it_IT`, `pt_BR`, `nl_NL`, `pl_PL`, `ja_JP`, `ko_KR`, `zh_CN` (all UTF-8).
Example for Swedish:
```bash ```bash
LANG=sv_SE.UTF-8 LANG=sv_SE.UTF-8
@@ -133,6 +135,15 @@ LANGUAGE=sv_SE:sv
LC_ALL=sv_SE.UTF-8 LC_ALL=sv_SE.UTF-8
``` ```
To add a locale not in the list, run inside the container:
```bash
sudo sed -i '/xx_XX.UTF-8/s/^# //g' /etc/locale.gen
sudo locale-gen
```
Replace `xx_XX` with the desired locale (e.g. `ru_RU`, `tr_TR`). This change does not persist across container restarts — for permanent additions, build from source and modify the Dockerfile.
## Initial Setup ## Initial Setup
### 1. Create host directories ### 1. Create host directories
@@ -454,7 +465,7 @@ docker compose run --rm devbox bash # interactive shell
- **opencode** — AI coding assistant - **opencode** — AI coding assistant
- **Node.js 22** — for npx-based MCP servers - **Node.js 22** — for npx-based MCP servers
- **AWS CLI v2** — SSO and Bedrock authentication - **AWS CLI v2** — SSO and Bedrock authentication
- **Dev tools** — git, git-lfs, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, jq, make, curl, wget, neovim 0.12, tmux, htop, tree - **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, jq, make, curl, wget, neovim 0.12, tmux, htop, tree
- **Non-root user** — runs as `developer` with UID auto-matched to workspace owner (sudo available) - **Non-root user** — runs as `developer` with UID auto-matched to workspace owner (sudo available)
### OMOS image (`latest-omos`) ### OMOS image (`latest-omos`)
+8 -5
View File
@@ -5,7 +5,7 @@ ARG DEBIAN_VERSION=trixie-slim
FROM debian:${DEBIAN_VERSION} AS base FROM debian:${DEBIAN_VERSION} AS base
ARG TARGETARCH ARG TARGETARCH
ARG OPENCODE_VERSION=1.4.7 ARG OPENCODE_VERSION=1.4.12
LABEL maintainer="joakimp" LABEL maintainer="joakimp"
LABEL description="Portable opencode developer container" LABEL description="Portable opencode developer container"
@@ -32,6 +32,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
make \ make \
patch \ patch \
diffutils \ diffutils \
git-crypt \
age \
sudo \ sudo \
locales \ locales \
procps \ procps \
@@ -71,7 +73,7 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "arm64" ;
nvim --version | head -1 nvim --version | head -1
# bat — syntax-highlighted cat replacement # bat — syntax-highlighted cat replacement
ARG BAT_VERSION=0.25.0 ARG BAT_VERSION=0.26.1
RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \
curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${ARCH}-unknown-linux-musl.tar.gz" | tar -xz -C /tmp && \ curl -fsSL "https://github.com/sharkdp/bat/releases/download/v${BAT_VERSION}/bat-v${BAT_VERSION}-${ARCH}-unknown-linux-musl.tar.gz" | tar -xz -C /tmp && \
install /tmp/bat-v${BAT_VERSION}-${ARCH}-unknown-linux-musl/bat /usr/local/bin/bat && \ install /tmp/bat-v${BAT_VERSION}-${ARCH}-unknown-linux-musl/bat /usr/local/bin/bat && \
@@ -91,7 +93,7 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64"
zoxide --version zoxide --version
# uv — fast Python package manager (replaces pip, venv, pyenv) # uv — fast Python package manager (replaces pip, venv, pyenv)
ARG UV_VERSION=0.11.6 ARG UV_VERSION=0.11.7
RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \
curl -fsSL "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${ARCH}-unknown-linux-musl.tar.gz" | tar -xz -C /tmp && \ curl -fsSL "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${ARCH}-unknown-linux-musl.tar.gz" | tar -xz -C /tmp && \
install /tmp/uv-${ARCH}-unknown-linux-musl/uv /usr/local/bin/uv && \ install /tmp/uv-${ARCH}-unknown-linux-musl/uv /usr/local/bin/uv && \
@@ -108,7 +110,8 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64"
chmod +x /usr/local/bin/rustup-init chmod +x /usr/local/bin/rustup-init
# Set locale — generate common UTF-8 locales (override via LANG/LC_ALL env vars) # 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 # To add more locales, run: sudo sed -i '/<locale>.UTF-8/s/^# //g' /etc/locale.gen && sudo locale-gen
RUN sed -i -E '/(en_US|en_GB|sv_SE|da_DK|nb_NO|fi_FI|de_DE|fr_FR|es_ES|it_IT|pt_BR|nl_NL|pl_PL|ja_JP|ko_KR|zh_CN)\.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG=en_US.UTF-8 ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8 ENV LC_ALL=en_US.UTF-8
@@ -148,7 +151,7 @@ RUN if [ "${INSTALL_PYTHON}" = "true" ]; then \
# ── Optional: Go ───────────────────────────────────────────────────── # ── Optional: Go ─────────────────────────────────────────────────────
ARG INSTALL_GO=false ARG INSTALL_GO=false
ARG GO_VERSION=1.23.4 ARG GO_VERSION=1.26.2
RUN if [ "${INSTALL_GO}" = "true" ]; then \ RUN if [ "${INSTALL_GO}" = "true" ]; then \
GOARCH=$(case "${TARGETARCH}" in amd64) echo "amd64" ;; arm64) echo "arm64" ;; *) echo "amd64" ;; esac) && \ GOARCH=$(case "${TARGETARCH}" in amd64) echo "amd64" ;; arm64) echo "arm64" ;; *) echo "amd64" ;; esac) && \
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xz && \ curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xz && \
+34 -1
View File
@@ -271,6 +271,39 @@ volumes:
- devbox-vscode:/home/developer/.vscode-server - devbox-vscode:/home/developer/.vscode-server
``` ```
### Shared machine setup (multiple users, single OS account)
For machines where multiple users share one OS account (e.g. a common `garage` user), a separate compose file isolates each user's config and data using a `SIGNUM` variable.
Each user creates their own directory and setup:
```bash
# Replace <signum> with your username/identifier
mkdir -p ~/<signum>/opencode-devbox
cd ~/<signum>/opencode-devbox
# Copy the shared-machine compose and env files
cp /path/to/opencode-devbox/docker-compose.shared.yml docker-compose.yml
cp /path/to/opencode-devbox/.env.shared.example .env
# Create per-user config directory
mkdir -p ~/<signum>/.config/opencode
# Edit .env with your signum, provider, keys, etc.
vim .env
# Start
docker compose up -d
docker compose exec -u developer devbox-<signum> opencode
```
Each user's container, config, and named volumes are fully isolated:
- Container name: `devbox-<signum>` (no collisions)
- Named volumes: prefixed with the project directory name (automatic per-user isolation)
- Opencode config: `~/<signum>/.config/opencode/` (per-user settings, OMOS config, etc.)
See `docker-compose.shared.yml` and `.env.shared.example` for the full configuration.
### Rebuilding the Image ### Rebuilding the Image
`docker compose run` and `docker compose up` use the existing image — they **do not rebuild** when you change the Dockerfile or build args (e.g. updating `OPENCODE_VERSION`). Rebuild explicitly: `docker compose run` and `docker compose up` use the existing image — they **do not rebuild** when you change the Dockerfile or build args (e.g. updating `OPENCODE_VERSION`). Rebuild explicitly:
@@ -445,7 +478,7 @@ Container (Debian trixie)
├── oh-my-opencode-slim (optional — multi-agent orchestration plugin, includes Bun) ├── oh-my-opencode-slim (optional — multi-agent orchestration plugin, includes Bun)
├── AWS CLI v2 (SSO + Bedrock auth) ├── AWS CLI v2 (SSO + Bedrock auth)
├── neovim 0.12, tmux, htop, bat, eza, zoxide, uv, rustup, make ├── neovim 0.12, tmux, htop, bat, eza, zoxide, uv, rustup, make
├── git, ssh, ripgrep, fd, fzf, jq, curl, tree ├── git, git-crypt, age, ssh, ripgrep, fd, fzf, jq, curl, tree
├── Node.js (for MCP servers) ├── Node.js (for MCP servers)
├── Bun (optional — included with oh-my-opencode-slim) ├── Bun (optional — included with oh-my-opencode-slim)
├── entrypoint.sh (UID adjustment, git config, provider setup) ├── entrypoint.sh (UID adjustment, git config, provider setup)
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
# check-versions.sh — Compare pinned versions in Dockerfile against latest releases
# Run before tagging a release to see what can be bumped.
set -euo pipefail
BOLD="\033[1m"; DIM="\033[2m"; GREEN="\033[32m"; YELLOW="\033[33m"; RESET="\033[0m"
DOCKERFILE="${1:-Dockerfile}"
if [[ ! -f "$DOCKERFILE" ]]; then
echo "Usage: $0 [Dockerfile]"
exit 1
fi
get_pinned() {
grep "^ARG $1=" "$DOCKERFILE" | head -1 | cut -d= -f2
}
get_latest_github() {
local repo="$1"
local tag
tag=$(curl -s "https://api.github.com/repos/${repo}/releases/latest" | jq -r '.tag_name // empty')
# Strip leading 'v' if present
echo "${tag#v}"
}
get_latest_go() {
curl -s "https://go.dev/dl/?mode=json" | jq -r '.[0].version' | sed 's/^go//'
}
get_latest_npm() {
npm view "$1" version 2>/dev/null
}
check() {
local name="$1" current="$2" latest="$3"
if [[ -z "$latest" ]]; then
printf " ${DIM}%-20s %-12s (could not check)${RESET}\n" "$name" "$current"
elif [[ "$current" == "$latest" ]]; then
printf " ${GREEN}%-20s %-12s ✓ up to date${RESET}\n" "$name" "$current"
else
printf " ${YELLOW}${BOLD}%-20s %-12s → %s available${RESET}\n" "$name" "$current" "$latest"
fi
}
echo ""
echo -e "${BOLD}Version check for $DOCKERFILE${RESET}"
echo ""
# GitHub-sourced binaries
check "opencode" "$(get_pinned OPENCODE_VERSION)" "$(get_latest_npm opencode-ai)"
check "gosu" "$(get_pinned GOSU_VERSION)" "$(get_latest_github tianon/gosu)"
check "fzf" "$(get_pinned FZF_VERSION)" "$(get_latest_github junegunn/fzf)"
check "git-lfs" "$(get_pinned GIT_LFS_VERSION)" "$(get_latest_github git-lfs/git-lfs)"
check "neovim" "$(get_pinned NVIM_VERSION)" "$(get_latest_github neovim/neovim)"
check "bat" "$(get_pinned BAT_VERSION)" "$(get_latest_github sharkdp/bat)"
check "eza" "$(get_pinned EZA_VERSION)" "$(get_latest_github eza-community/eza)"
check "zoxide" "$(get_pinned ZOXIDE_VERSION)" "$(get_latest_github ajeetdsouza/zoxide)"
check "uv" "$(get_pinned UV_VERSION)" "$(get_latest_github astral-sh/uv)"
check "Go (opt)" "$(get_pinned GO_VERSION)" "$(get_latest_go)"
echo ""
echo -e "${DIM}Node.js uses major version ($(get_pinned NODE_VERSION)) — auto-updates via nodesource.${RESET}"
echo -e "${DIM}rustup-init uses latest from static.rust-lang.org — no pinned version.${RESET}"
echo -e "${DIM}Debian apt packages update on each build via apt-get update.${RESET}"
echo ""
+50
View File
@@ -0,0 +1,50 @@
# opencode-devbox docker-compose for shared machines
#
# For machines where multiple users share one OS account (e.g. 'garage').
# Each user gets isolated config, data, and named volumes by setting
# SIGNUM in their .env file.
#
# Setup per user:
# 1. mkdir -p ~/<signum>/opencode-devbox && cd ~/<signum>/opencode-devbox
# 2. cp docker-compose.shared.yml docker-compose.yml
# 3. cp .env.shared.example .env
# 4. Edit .env with your signum, provider, keys, etc.
# 5. mkdir -p ~/<signum>/.config/opencode
# 6. docker compose up -d
#
# Named volumes are automatically isolated per user because Docker Compose
# prefixes them with the project directory name (e.g. opencode-devbox_devbox-data).
# Since each user runs from ~/<signum>/opencode-devbox/, volumes don't collide.
services:
devbox:
image: joakimp/opencode-devbox:latest
container_name: devbox-${SIGNUM:?Set SIGNUM in .env}
stdin_open: true
tty: true
env_file:
- .env
environment:
- TERM=xterm-256color
volumes:
# Host workspace — user's project directory
- ${WORKSPACE_PATH:-~/src}:/workspace
# SSH keys — user-specific if available, else shared
- ${SSH_KEY_PATH:-~/.ssh}:/home/developer/.ssh:ro
# Opencode config — per-user (persists settings across restarts)
- ${HOME}/${SIGNUM}/.config/opencode:/home/developer/.config/opencode
# Persist opencode data (auth, memory, session history)
- devbox-data:/home/developer/.local/share/opencode
# Persist uv data (Python installs)
- devbox-uv:/home/developer/.local/share/uv
# Optional: AWS credentials (per-user if available)
# - ${HOME}/${SIGNUM}/.aws:/home/developer/.aws
volumes:
devbox-data:
devbox-uv: