Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3669bec8ff | |||
| f210d533eb | |||
| 00d4f1596d | |||
| 3c19b836cf | |||
| fffaeffb7a | |||
| b4d2f09e77 | |||
| d74adc14dc | |||
| 9fa8b5c1e3 | |||
| 3724519402 | |||
| a06dc5f47c | |||
| 967ce7df49 | |||
| c209d873ba | |||
| e52ac46237 | |||
| 83fb3d6de5 |
+1
-1
@@ -7,7 +7,7 @@
|
||||
OPENCODE_PROVIDER=anthropic
|
||||
|
||||
# Model override (optional, defaults per provider)
|
||||
# OPENCODE_MODEL=anthropic/claude-sonnet-4-5
|
||||
# OPENCODE_MODEL=anthropic/claude-sonnet-4-6
|
||||
|
||||
# ── API Keys (set the one matching your provider) ────────────────────
|
||||
# ANTHROPIC_API_KEY=
|
||||
|
||||
@@ -3,3 +3,6 @@
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Personal cloud-init overrides (not shared)
|
||||
deploy/my-cloud-init.yml
|
||||
|
||||
+12
-6
@@ -226,24 +226,26 @@ Understanding what survives container restarts and what doesn't:
|
||||
| `/home/developer/.ssh` | Host bind mount (ro) | ✅ Yes — lives on host | SSH keys |
|
||||
| `/home/developer/.aws` | Host bind mount | ✅ Yes — lives on host | AWS credentials/SSO cache |
|
||||
| `/home/developer/.local/share/opencode` | Named volume (if configured) | ✅ Yes — Docker volume | Session history, memory, auth tokens |
|
||||
| `/home/developer/.local/state/opencode` | Named volume (if configured) | ✅ Yes — Docker volume | TUI settings (theme, toggles) |
|
||||
| `/home/developer/.local/share/uv` | Named volume (if configured) | ✅ Yes — Docker volume | Python installs, uv tool installs |
|
||||
| `/home/developer/.rustup` | Named volume (if configured) | ✅ Yes — Docker volume | Rust toolchains |
|
||||
| `/home/developer/.cargo` | Named volume (if configured) | ✅ Yes — Docker volume | Cargo binaries, registry cache |
|
||||
| `/home/developer/.vscode-server` | Named volume (if configured) | ✅ Yes — Docker volume | VS Code server and extensions |
|
||||
| `/home/developer/.config/opencode` | Host bind mount (if configured) | ✅ Yes — lives on host | opencode.json, oh-my-opencode-slim.json, skills |
|
||||
| `/home/developer/.config/opencode` | Host bind mount (if configured) | ✅ Yes — lives on host | opencode.json, skills, plus `oh-my-opencode-slim.json` on the OMOS variant |
|
||||
|
||||
### Key points
|
||||
|
||||
- **Project files** (`/workspace`) are always safe — they're your host filesystem.
|
||||
- **opencode config** is auto-generated from `OPENCODE_PROVIDER` env var on each start if no existing config is found. To persist config changes, mount the config directory from the host (see Custom opencode Config below).
|
||||
- **opencode data** (session history, memory) is lost with `--rm` unless you add a named volume.
|
||||
- **Python installs** via `uv python install` are lost unless you add the `devbox-uv` named volume.
|
||||
- **Rust toolchains** via `rustup-init` are lost unless you add the `devbox-rustup` and `devbox-cargo` named volumes.
|
||||
- **opencode data** (session history, memory) is lost on container recreation unless you add a named volume.
|
||||
- **TUI settings** (theme, toggles) are lost on container recreation unless you add the `devbox-state` named volume.
|
||||
- **Python installs** via `uv python install` are lost on container recreation unless you add the `devbox-uv` named volume.
|
||||
- **Rust toolchains** via `rustup-init` are lost on container recreation unless you add the `devbox-rustup` and `devbox-cargo` named volumes.
|
||||
- **AWS SSO tokens** persist across restarts when `~/.aws` is mounted (recommended for Bedrock users).
|
||||
|
||||
## Custom opencode Config
|
||||
|
||||
For full control over opencode settings (MCP servers, custom models, oh-my-opencode-slim agents, etc.), mount the entire config directory from the host:
|
||||
For full control over opencode settings (MCP servers, custom models, and — on the OMOS variant — oh-my-opencode-slim agents), mount the entire config directory from the host:
|
||||
|
||||
```bash
|
||||
docker run -it --rm \
|
||||
@@ -254,6 +256,8 @@ docker run -it --rm \
|
||||
|
||||
This persists all configuration changes across container restarts. When an existing `opencode.json` is found, the `OPENCODE_PROVIDER` auto-config is skipped.
|
||||
|
||||
> **Portability note:** The mounted config runs inside a Linux container. Any absolute paths inside `opencode.json` (for example, host-specific `plugin` entries like `file:///usr/local/lib/node_modules/...` or `file:///opt/homebrew/...`) will not resolve inside the container. Prefer bare package specifiers (e.g. `"oh-my-opencode-slim"`) that resolve via `node_modules` lookup, which works on both macOS and Linux hosts.
|
||||
|
||||
## Neovim Configuration
|
||||
|
||||
The image includes neovim 0.12 with `EDITOR=nvim` set by default. To use your own neovim config (and have plugins auto-install via lazy.nvim on first start), mount it from the host:
|
||||
@@ -411,6 +415,7 @@ services:
|
||||
- ~/projects:/workspace
|
||||
- ~/.ssh:/home/developer/.ssh:ro
|
||||
- devbox-data:/home/developer/.local/share/opencode
|
||||
- devbox-state:/home/developer/.local/state/opencode
|
||||
- devbox-uv:/home/developer/.local/share/uv
|
||||
# Optional: persist Rust toolchains and cargo data
|
||||
# - devbox-rustup:/home/developer/.rustup
|
||||
@@ -428,6 +433,7 @@ services:
|
||||
|
||||
volumes:
|
||||
devbox-data:
|
||||
devbox-state:
|
||||
devbox-uv:
|
||||
# devbox-rustup:
|
||||
# devbox-cargo:
|
||||
@@ -465,7 +471,7 @@ docker compose run --rm devbox bash # interactive shell
|
||||
- **opencode** — AI coding assistant
|
||||
- **Node.js 22** — for npx-based MCP servers
|
||||
- **AWS CLI v2** — SSO and Bedrock authentication
|
||||
- **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
|
||||
- **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync
|
||||
- **Non-root user** — runs as `developer` with UID auto-matched to workspace owner (sudo available)
|
||||
|
||||
### OMOS image (`latest-omos`)
|
||||
|
||||
+4
-1
@@ -5,7 +5,7 @@ ARG DEBIAN_VERSION=trixie-slim
|
||||
FROM debian:${DEBIAN_VERSION} AS base
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG OPENCODE_VERSION=1.14.18
|
||||
ARG OPENCODE_VERSION=1.14.19
|
||||
|
||||
LABEL maintainer="joakimp"
|
||||
LABEL description="Portable opencode developer container"
|
||||
@@ -39,6 +39,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
locales \
|
||||
procps \
|
||||
unzip \
|
||||
gcc \
|
||||
g++ \
|
||||
rsync \
|
||||
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -128,14 +128,16 @@ docker compose exec -u developer devbox aws --version
|
||||
|
||||
### Custom opencode config
|
||||
|
||||
For full control over opencode settings (MCP servers, custom models, oh-my-opencode-slim agents, etc.), mount the entire config directory from the host:
|
||||
For full control over opencode settings (MCP servers, custom models, and — on the OMOS variant — oh-my-opencode-slim agents), mount the entire config directory from the host:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ~/.config/opencode:/home/developer/.config/opencode
|
||||
```
|
||||
|
||||
This persists all configuration changes across container restarts, including `opencode.json`, `oh-my-opencode-slim.json`, and skills. When an existing `opencode.json` is found, the `OPENCODE_PROVIDER` auto-config is skipped.
|
||||
This persists all configuration changes across container restarts, including `opencode.json`, skills, and (on the OMOS variant) `oh-my-opencode-slim.json`. When an existing `opencode.json` is found, the `OPENCODE_PROVIDER` auto-config is skipped.
|
||||
|
||||
> **Portability note:** The mounted config runs inside a Linux container. Any absolute paths inside `opencode.json` (for example, host-specific `plugin` entries like `file:///usr/local/lib/node_modules/...` or `file:///opt/homebrew/...`) will not resolve inside the container. Prefer bare package specifiers (e.g. `"oh-my-opencode-slim"`) that resolve via `node_modules` lookup, which works on both macOS and Linux hosts.
|
||||
|
||||
### Custom skills
|
||||
|
||||
@@ -477,7 +479,7 @@ Container (Debian trixie)
|
||||
├── opencode binary
|
||||
├── oh-my-opencode-slim (optional — multi-agent orchestration plugin, includes Bun)
|
||||
├── 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, gcc, g++, rsync
|
||||
├── git, git-crypt, age, ssh, ripgrep, fd, fzf, jq, curl, tree
|
||||
├── Node.js (for MCP servers)
|
||||
├── Bun (optional — included with oh-my-opencode-slim)
|
||||
@@ -493,11 +495,12 @@ Container (Debian trixie)
|
||||
| `/home/developer/.ssh` | Host bind mount (ro) | ✅ Yes | SSH keys |
|
||||
| `/home/developer/.aws` | Host bind mount (if configured) | ✅ Yes | AWS credentials/SSO cache |
|
||||
| `/home/developer/.local/share/opencode` | Named volume `devbox-data` | ✅ Yes | Session history, memory |
|
||||
| `/home/developer/.local/state/opencode` | Named volume `devbox-state` | ✅ Yes | TUI settings (theme, toggles) |
|
||||
| `/home/developer/.local/share/uv` | Named volume `devbox-uv` (if configured) | ✅ Yes | Python installs, uv tool installs |
|
||||
| `/home/developer/.rustup` | Named volume `devbox-rustup` (if configured) | ✅ Yes | Rust toolchains |
|
||||
| `/home/developer/.cargo` | Named volume `devbox-cargo` (if configured) | ✅ Yes | Cargo binaries, registry cache |
|
||||
| `/home/developer/.vscode-server` | Named volume `devbox-vscode` (if configured) | ✅ Yes | VS Code server and extensions |
|
||||
| `/home/developer/.config/opencode` | Host bind mount (if configured) | ✅ Yes | opencode.json, oh-my-opencode-slim.json, skills |
|
||||
| `/home/developer/.config/opencode` | Host bind mount (if configured) | ✅ Yes | opencode.json, skills, plus `oh-my-opencode-slim.json` on the OMOS variant |
|
||||
|
||||
**opencode config** (`opencode.json`) is auto-generated from `OPENCODE_PROVIDER` on each start. It sets provider and model only — no MCP servers. To persist config changes and use custom settings, mount the config directory from the host (see Custom opencode config above).
|
||||
|
||||
|
||||
@@ -113,9 +113,13 @@ for entry in "${MOUNT_PATTERNS[@]}"; do
|
||||
ssh_cmd "mkdir -p ${remote_path}"
|
||||
|
||||
# Sync with rsync (fall back to scp if rsync unavailable)
|
||||
# Exclude generated/cached content that gets recreated on the remote
|
||||
# Exclude generated/cached content that gets recreated on the remote.
|
||||
# Use -rlptD (archive minus -o -g) so ownership on the remote is set
|
||||
# by the receiving user (devbox). Preserving host UID/GID with -a
|
||||
# tagged files with the pusher's numeric GID, which leaked through
|
||||
# whenever the VM happened to have a matching group (see #group-1001).
|
||||
if command -v rsync &>/dev/null; then
|
||||
rsync -az --progress \
|
||||
rsync -rlptDz --progress \
|
||||
--exclude='node_modules' \
|
||||
--exclude='__pycache__' \
|
||||
--exclude='.venv' \
|
||||
|
||||
@@ -49,6 +49,9 @@ services:
|
||||
# Optional: persist opencode data (auth, memory, etc.)
|
||||
- devbox-data:/home/developer/.local/share/opencode
|
||||
|
||||
# Optional: persist opencode TUI settings (theme, toggles, etc.)
|
||||
- devbox-state:/home/developer/.local/state/opencode
|
||||
|
||||
# Optional: persist uv data (Python installs, tool installs)
|
||||
# Without this, 'uv python install' must be re-run after container removal.
|
||||
- devbox-uv:/home/developer/.local/share/uv
|
||||
@@ -66,6 +69,7 @@ services:
|
||||
|
||||
volumes:
|
||||
devbox-data:
|
||||
devbox-state:
|
||||
devbox-uv:
|
||||
# devbox-rustup:
|
||||
# devbox-cargo:
|
||||
|
||||
+4
-4
@@ -22,7 +22,7 @@ if [ ! -f "$CONFIG_FILE" ] && [ -n "${OPENCODE_PROVIDER:-}" ]; then
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"\$schema": "https://opencode.ai/config.json",
|
||||
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-5}",
|
||||
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-6}",
|
||||
"share": "disabled",
|
||||
"autoupdate": false
|
||||
}
|
||||
@@ -32,7 +32,7 @@ EOF
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"\$schema": "https://opencode.ai/config.json",
|
||||
"model": "${OPENCODE_MODEL:-openai/gpt-4o}",
|
||||
"model": "${OPENCODE_MODEL:-openai/gpt-5.4}",
|
||||
"share": "disabled",
|
||||
"autoupdate": false
|
||||
}
|
||||
@@ -42,7 +42,7 @@ EOF
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"\$schema": "https://opencode.ai/config.json",
|
||||
"model": "${OPENCODE_MODEL:-amazon-bedrock/anthropic.claude-sonnet-4-5-v1}",
|
||||
"model": "${OPENCODE_MODEL:-amazon-bedrock/global.anthropic.claude-sonnet-4-5-20250929-v1:0}",
|
||||
"share": "disabled",
|
||||
"autoupdate": false,
|
||||
"provider": {
|
||||
@@ -60,7 +60,7 @@ EOF
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"\$schema": "https://opencode.ai/config.json",
|
||||
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-5}",
|
||||
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-6}",
|
||||
"share": "disabled",
|
||||
"autoupdate": false
|
||||
}
|
||||
|
||||
@@ -51,8 +51,25 @@ fi
|
||||
# developer user can write to them.
|
||||
FINAL_UID="${TARGET_UID:-$CURRENT_UID}"
|
||||
FINAL_GID="${TARGET_GID:-$CURRENT_GID}"
|
||||
|
||||
# First, fix parent dirs that Docker auto-creates as root:root when it
|
||||
# materializes nested mount points (e.g. mounting a volume at
|
||||
# .local/state/opencode creates .local/state as root). Non-recursive —
|
||||
# we only need the dir node itself; children are handled below or were
|
||||
# created by the user.
|
||||
for parent in \
|
||||
/home/"$USER_NAME"/.local \
|
||||
/home/"$USER_NAME"/.local/share \
|
||||
/home/"$USER_NAME"/.local/state \
|
||||
/home/"$USER_NAME"/.config; do
|
||||
if [ -d "$parent" ] && [ "$(stat -c '%u' "$parent" 2>/dev/null)" != "$FINAL_UID" ]; then
|
||||
chown "$FINAL_UID":"$FINAL_GID" "$parent" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
for dir in \
|
||||
/home/"$USER_NAME"/.local/share/opencode \
|
||||
/home/"$USER_NAME"/.local/state/opencode \
|
||||
/home/"$USER_NAME"/.local/share/uv \
|
||||
/home/"$USER_NAME"/.rustup \
|
||||
/home/"$USER_NAME"/.cargo \
|
||||
|
||||
Reference in New Issue
Block a user