The ONNX embedding model (~79 MB) downloads to ~/.cache/chroma/ on first mempalace search. Without persistence it re-downloads on every container recreation. Add a separate devbox-chroma-cache volume rather than mixing it into the palace data volume — model cache is disposable (delete and re-download), palace data is precious (back up and migrate). Both volumes are commented out by default (opt-in). Updated README.md storage section to explain the two-volume split and the air-gapped pre-population path. Added chroma cache row to DOCKER_HUB.md data storage table.
21 KiB
opencode-devbox — Docker Hub
Portable AI developer environment for opencode. Debian-based, with git, SSH, Node.js, AWS CLI v2, and common dev tools pre-installed.
Image Variants
Two image variants are published for each release:
| Tag | Description |
|---|---|
latest / vX.Y.Z |
Base image — opencode, Node.js, AWS CLI, dev tools |
latest-omos / vX.Y.Z-omos |
Base + oh-my-opencode-slim multi-agent orchestration and Bun |
Both variants support linux/amd64 and linux/arm64.
Quick Start
docker run -it --rm \
-e ANTHROPIC_API_KEY=your-key \
-e OPENCODE_PROVIDER=anthropic \
-e GIT_USER_NAME="Your Name" \
-e GIT_USER_EMAIL="you@example.com" \
-v ~/projects:/workspace \
-v ~/.ssh:/home/developer/.ssh:ro \
joakimp/opencode-devbox:latest
This drops you straight into opencode with your project mounted at /workspace.
Interactive Shell
To get a shell first (useful for AWS SSO login or running other commands):
docker run -it --rm \
-e ANTHROPIC_API_KEY=your-key \
-e OPENCODE_PROVIDER=anthropic \
-v ~/projects:/workspace \
-v ~/.ssh:/home/developer/.ssh:ro \
joakimp/opencode-devbox:latest bash
Then run opencode when ready.
Running Multiple Shells
Once opencode is running it takes over the terminal. To have a separate shell for aws, git, or other commands, run the container in the background and attach multiple times:
# Start in background
docker run -d --name devbox \
-e ANTHROPIC_API_KEY=your-key \
-e OPENCODE_PROVIDER=anthropic \
-v ~/projects:/workspace \
-v ~/.ssh:/home/developer/.ssh:ro \
joakimp/opencode-devbox:latest sleep infinity
# Shell 1: run opencode
docker exec -it -u developer devbox opencode
# Shell 2 (separate terminal): aws, git, etc.
docker exec -it -u developer devbox bash
# When done
docker rm -f devbox
Note: Always use
-u developerwithdocker exec— the container starts as root for UID adjustment, then drops todeveloper. Without-u developer, exec runs as root.
Environment Variables
All configuration is done via environment variables, typically stored in a .env file.
Provider Configuration
| Variable | Description | Default |
|---|---|---|
OPENCODE_PROVIDER |
LLM provider (anthropic, openai, amazon-bedrock) |
anthropic |
OPENCODE_MODEL |
Model override | Provider default |
API Keys
Set the key matching your provider:
| Variable | Provider |
|---|---|
ANTHROPIC_API_KEY |
Anthropic |
OPENAI_API_KEY |
OpenAI |
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY |
AWS Bedrock (static creds) |
AWS Bedrock
| Variable | Description | Default |
|---|---|---|
AWS_REGION |
AWS region | us-east-1 |
AWS_PROFILE |
AWS SSO profile name | default |
Git
| Variable | Description |
|---|---|
GIT_USER_NAME |
Git commit author name |
GIT_USER_EMAIL |
Git commit author email |
User ID Mapping
The container runs as user developer (UID 1000 by default). If your host user has a different UID, file permission mismatches can occur on mounted volumes.
The entrypoint automatically detects the owner of /workspace and adjusts the container user's UID/GID to match. You can also set it explicitly:
| Variable | Description | Default |
|---|---|---|
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 |
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:
LANG=sv_SE.UTF-8
LANGUAGE=sv_SE:sv
LC_ALL=sv_SE.UTF-8
To add a locale not in the list, run inside the container:
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
1. Create host directories
Bind-mounted directories must exist on the host before starting the container. Docker creates missing directories as root-owned, which causes permission issues.
# Required
mkdir -p ~/projects
# If mounting opencode config (recommended for persistent settings)
mkdir -p ~/.config/opencode
# If using AWS Bedrock
# mkdir -p ~/.aws
# If mounting neovim config
# mkdir -p ~/.config/nvim
2. Create a .env file
Create a .env file with your configuration. Examples for each provider:
Anthropic:
OPENCODE_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
GIT_USER_NAME=Your Name
GIT_USER_EMAIL=you@example.com
OpenAI:
OPENCODE_PROVIDER=openai
OPENAI_API_KEY=sk-...
GIT_USER_NAME=Your Name
GIT_USER_EMAIL=you@example.com
AWS Bedrock (SSO):
OPENCODE_PROVIDER=amazon-bedrock
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
GIT_USER_EMAIL=you@example.com
3. AWS SSO setup (Bedrock users only)
AWS SSO requires a ~/.aws/config file on the host with your SSO session configuration. If you already have this on another machine, copy it:
scp -r user@other-machine:~/.aws ~/.aws
Or configure from scratch:
aws configure sso
You'll be prompted for:
- SSO session name
- SSO start URL
- SSO region
- Registration scopes (typically
sso:account:access)
The ~/.aws directory must be mounted into the container (see docker-compose example below).
Data Storage and Persistence
Understanding what survives container restarts and what doesn't:
| Path in container | Source | Survives restart? | Contains |
|---|---|---|---|
/workspace |
Host bind mount | ✅ Yes — lives on host | Your project files |
/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/.cache/bash |
Named volume devbox-shell-history |
✅ Yes — Docker volume | Bash history ($HISTFILE) — survives container recreate |
/home/developer/.local/share/zoxide |
Named volume devbox-zoxide |
✅ Yes — Docker volume | Zoxide directory history (z <fragment> jump targets) |
/home/developer/.local/share/nvim |
Named volume devbox-nvim-data |
✅ Yes — Docker volume | Neovim plugins, Mason LSP installs, Lazy plugin cache |
/home/developer/.mempalace |
Named volume devbox-palace (if configured) |
✅ Yes — Docker volume | MemPalace conversation memory, knowledge graph, embeddings |
/home/developer/.cache/chroma |
Named volume devbox-chroma-cache (if configured) |
✅ Yes — Docker volume | ChromaDB ONNX embedding model (~79 MB, downloaded on first use) |
/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, 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_PROVIDERenv 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 on container recreation unless you add a named volume.
- TUI settings (theme, toggles) are lost on container recreation unless you add the
devbox-statenamed volume. - Bash history persists via the
devbox-shell-historyvolume mounted at~/.cache/bash.HISTFILEis pre-configured; no setup required. - Python installs via
uv python installare lost on container recreation unless you add thedevbox-uvnamed volume. - Rust toolchains via
rustup-initare lost on container recreation unless you add thedevbox-rustupanddevbox-cargonamed volumes. - AWS SSO tokens persist across restarts when
~/.awsis mounted (recommended for Bedrock users).
Custom opencode Config
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:
docker run -it --rm \
-v ~/.config/opencode:/home/developer/.config/opencode \
... \
joakimp/opencode-devbox:latest
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-specificpluginentries likefile:///usr/local/lib/node_modules/...orfile:///opt/homebrew/...) will not resolve inside the container. Prefer bare package specifiers (e.g."oh-my-opencode-slim") that resolve vianode_moduleslookup, 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:
docker run -it --rm \
-v ~/.config/nvim:/home/developer/.config/nvim:ro \
... \
joakimp/opencode-devbox:latest
Python Development with uv
The image includes Python 3.13 (from Debian Trixie) and uv, a fast Python package manager that replaces pip, venv, and pyenv:
# Python 3.13 is available out of the box
python3 --version
# Use uv for package management
uv venv
uv pip install -r requirements.txt
# Or use uv's project workflow (reads pyproject.toml)
uv sync
# Run a Python script
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:
docker run -it --rm \
-v devbox-uv:/home/developer/.local/share/uv \
... \
joakimp/opencode-devbox:latest
Project virtual environments (.venv) are stored in your workspace directory and persist automatically via the /workspace bind mount.
Rust Development with rustup
The image includes rustup-init, the Rust toolchain installer. Rust is not pre-installed but can be bootstrapped on demand:
# One-time setup: install Rust toolchain (~300MB, persists with volumes)
rustup-init -y
source ~/.cargo/env
# Now use Rust normally
cargo new my-project
cargo build
cargo run
To persist Rust toolchains and cargo data across container restarts, add named volumes:
docker run -it --rm \
-v devbox-rustup:/home/developer/.rustup \
-v devbox-cargo:/home/developer/.cargo \
... \
joakimp/opencode-devbox:latest
JavaScript and TypeScript
The base image includes Node.js 22 and npm — sufficient for most JavaScript and TypeScript development:
# Initialize a new project
npm init -y
# Install dependencies
npm install
# Run TypeScript (via tsx, ts-node, etc.)
npx tsx src/index.ts
The OMOS image variant also includes Bun, a faster JavaScript runtime and package manager:
bun init
bun install
bun run src/index.ts
Node modules are stored in your project directory under /workspace and persist automatically.
VS Code Integration
VS Code can connect directly to a running opencode-devbox container for a full IDE experience with IntelliSense, debugging, and extensions running inside the container.
Requirements: Install the Dev Containers extension. For remote Docker hosts, also install Remote - SSH.
Steps:
- Start the container:
docker compose up -d - In VS Code:
Ctrl+Shift+P→ "Dev Containers: Attach to Running Container" → selectopencode-devbox
For remote Docker hosts (e.g. connecting to a server via SSH), first connect to the remote host with Remote-SSH, then attach to the container from there.
VS Code extensions installed inside the container persist as long as the container exists. For persistent extension storage across container recreations, add a named volume:
docker run -it --rm \
-v devbox-vscode:/home/developer/.vscode-server \
... \
joakimp/opencode-devbox:latest
Using docker-compose
Create a directory with a docker-compose.yml and a .env file:
mkdir opencode-devbox && cd opencode-devbox
.env — your settings (never commit this):
OPENCODE_PROVIDER=amazon-bedrock
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
GIT_USER_EMAIL=you@example.com
docker-compose.yml:
services:
devbox:
image: joakimp/opencode-devbox:latest
# For multi-agent orchestration, use the omos variant instead:
# image: joakimp/opencode-devbox:latest-omos
container_name: opencode-devbox
stdin_open: true
tty: true
env_file:
- .env
environment:
- TERM=xterm-256color
volumes:
- ~/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
# - devbox-cargo:/home/developer/.cargo
# Optional: persist VS Code server and extensions
# - devbox-vscode:/home/developer/.vscode-server
# Mount AWS config for Bedrock SSO (required for amazon-bedrock provider)
# - ~/.aws:/home/developer/.aws
# Optional: mount opencode config directory (persists config changes across restarts)
# - ~/.config/opencode:/home/developer/.config/opencode
# Optional: mount opencode agent skills from host
# - ~/.agents/skills:/home/developer/.agents/skills:ro
# Optional: mount neovim config from host (plugins auto-install on first start)
# - ~/.config/nvim:/home/developer/.config/nvim:ro
volumes:
devbox-data:
devbox-state:
devbox-uv:
# devbox-rustup:
# devbox-cargo:
# devbox-vscode:
Docker Compose loads .env automatically from the same directory. All variables from .env are passed to the container via env_file. Do not hardcode provider settings in the environment: section — use .env instead.
Then:
# Start in background
docker compose up -d
# Open a shell (always use -u developer with exec)
docker compose exec -u developer devbox bash
# For Bedrock: authenticate, then start opencode
aws sso login --sso-session <your-session> --use-device-code
opencode
# Or run opencode directly (if no SSO needed)
docker compose exec -u developer devbox opencode
# One-shot mode (creates and removes container)
docker compose run --rm devbox # direct to opencode
docker compose run --rm devbox bash # interactive shell
Shell defaults
The image ships baked .bash_aliases and .inputrc in /etc/skel-devbox/. On first container start the entrypoint copies them to /home/developer/ only if the target file does not already exist, so your host bind-mounts or any in-container customization are preserved across upgrades.
- Prefix history search on Up/Down arrows (type
git, press Up, walk back through priorgit ...commands only). Ctrl-Up / Ctrl-Down still step through full history. - Persistent history via
$HISTFILE=~/.cache/bash/history, backed by thedevbox-shell-historynamed volume. Survives container recreate. 100 000 entries, time-stamped, dedup. - Case-insensitive tab completion and coloured completion lists.
- Aliases —
ls/ll/la→eza,cat→bat,gs/gd/glfor git, interactiverm/mv/cp. - Integrations —
zoxide(z <fragment>),fzfkey bindings (Ctrl-R,Ctrl-T). [devbox]prompt prefix so you always know you're in the container.
To override with your host's own files, uncomment the matching bind-mount lines in docker-compose.yml. To restore the baked defaults any time: cp /etc/skel-devbox/.bash_aliases ~/ (or delete the file and recreate the container).
What's Included
Base image (latest)
- Debian trixie-slim — glibc, full terminal/PTY support
- 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, mempalace, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync
- Non-root user — runs as
developerwith UID auto-matched to workspace owner (sudo available)
OMOS image (latest-omos)
Everything in the base image, plus:
- oh-my-opencode-slim — multi-agent orchestration plugin
- Bun — JavaScript runtime required by oh-my-opencode-slim
- 6 specialized agents — Orchestrator, Explorer, Oracle, Librarian, Designer, Fixer
Additional runtimes (build from source)
When building from source, additional runtimes are available via build args:
- Python 3 (
INSTALL_PYTHON=true) — Python 3 + pip + venv - Go (
INSTALL_GO=true) — Go toolchain
oh-my-opencode-slim (OMOS variant)
The -omos image variant includes oh-my-opencode-slim, which adds a multi-agent layer on top of opencode. An Orchestrator delegates tasks to specialized agents, each configurable with different models and providers.
Quick start with OMOS
docker run -it --rm \
-e OPENAI_API_KEY=your-key \
-e OPENCODE_PROVIDER=openai \
-e ENABLE_OMOS=true \
-v ~/projects:/workspace \
-v ~/.ssh:/home/developer/.ssh:ro \
joakimp/opencode-devbox:latest-omos
On first start, the entrypoint configures oh-my-opencode-slim automatically. The default preset uses OpenAI models.
OMOS environment variables
| Variable | Default | Description |
|---|---|---|
ENABLE_OMOS |
false |
Activate oh-my-opencode-slim on container start |
OMOS_TMUX |
false |
Enable tmux pane integration (watch agents in split panes) |
OMOS_SKILLS |
true |
Install recommended skills (simplify, agent-browser, cartography) |
OMOS_RESET |
false |
Force regenerate config on next start (backs up existing config) |
Custom OMOS configuration
If you mount the opencode config directory (see Custom opencode Config above), the oh-my-opencode-slim.json file is included and persists across restarts. Edit it directly to control which models power each agent, fallback chains, council setup, and more.
See the oh-my-opencode-slim configuration docs for the full reference.
Verifying agents
After starting opencode with OMOS enabled, run inside the opencode session:
ping all agents
All six agents should respond if your provider authentication is working.
Multi-User Setup
This guide covers single-user setup. For running multiple opencode-devbox instances in parallel — whether each user has their own OS account or everyone shares one login — see the Multi-user setup section in the source repository. It covers volume isolation, the docker-compose.shared.yml layout, and the SIGNUM / $USER auto-detection mechanism.
Source
Build from source or contribute: opencode-devbox on Gitea
See the Changelog for a full release history.