AI coding agents are powerful, but giving an agent unrestricted access to your development machine can be uncomfortable. You want the convenience of an AI-powered development workflow without turning your entire host system into the agent’s playground.
That’s where snowdon-dev/opencode-docker comes in.
OpenCode doesn’t impose an opinion on the sandbox its agents run in, and
opencode-docker takes advantage of that. It is a security- and
human-control-oriented workflow for running OpenCode
inside Docker containers. Your project is available inside the container at
/workspace/project, while toolchain caches for Go, Rust, Node.js and Python
persist between runs.
It also lets you manage multiple agents, including sub-agents, across distinct worktrees of your repository library — all through a simple CLI.
Every feature is security-first, and convenience features are opt-in. The result is a more portable, repeatable, and controllable environment for AI-assisted development.
Security and control are first-class concerns
The goal isn’t simply to put OpenCode inside Docker.
opencode-docker is designed around the idea of keeping the developer in control, and its security model is explicit about how:
- Workspace
.gitdirectories are mounted read-only, so history cannot be rewritten and commands cannot be injected (opt out withSD_READ_ONLY=false). - Read-only task runs:
opencode:ioandopencode:changes --outputmount the entire workspace read-only, with only the declared--outputpaths writable. - Each workspace gets its own Docker network, isolated from other workspaces.
- Toolchain caches and other host mounts are opt-in via
OPENCODE_CACHE. - Your API key travels as a file, never an environment variable — it never
appears in
docker inspectordocker compose config. - A workspace outside
$HOMEprompts before it is used, unlessSD_YOLO=true. - A worktree’s parent repository
.gitis also mounted read-only, keeping git usable while the worktree stays isolated.
Docker is not a complete security solution by itself, but running AI development tooling inside a deliberately configured container provides a more controlled workflow than giving every tool direct, unrestricted access to your host environment.
You still decide what gets mounted. You still control the configuration. And you can build a workflow that fits the way you work.
A secure API key, without environment variables
Secrets deserve their own mention. Put your API key in OPENCODE_KEY_FILE
(default ~/.config/opencode-docker/opencode.key); a non-empty file is mounted
into the container at /run/secrets/api_key and stays out of the container’s
environment entirely — it never appears in docker inspect or
docker compose config.
Your OpenCode config template reads the key from that path with a
{file:...} reference, so the secret lives in one file on your host and
nowhere else. If the file is missing or empty, the backend starts without a
key.
Why run OpenCode in Docker?
Modern development projects often depend on a growing collection of tools:
- Node.js and npm
- Python and pip
- Go
- Rust and Cargo
- Git and command-line utilities
- Project-specific dependencies
Installing everything directly on your host can quickly become messy. Different projects may need different tooling, caches can consume significant disk space, and AI agents operating directly on the host may have access to more than you intended.
With opencode-docker, OpenCode runs inside a Docker-based development
environment while your project workspace is mounted at /workspace/project.
This provides a useful boundary between your host system and the environment where your AI coding workflow operates.
How a session starts
The lifecycle is worth understanding, because it explains the design.
The opencode command (the start command) starts a backend inside the
container, waits for it to become healthy, then attaches a TUI — your host
opencode binary when one is on PATH, otherwise a one-off in-container tui
service. The backend is stopped when the TUI exits.
Commands that run tasks (run, changes, setup) use the running container
when there is one and a throwaway container otherwise; scaffold and bg
always use a throwaway container. io (and changes --output) always run on
their own, with the workspace mounted read-only.
Persistent caches without rebuilding everything
Containers are convenient, but constantly rebuilding dependencies is not.
opencode-docker supports persistent cache directories for multiple development ecosystems, including:
- OpenCode config, data and cache
- npm
- pip
- Go build and module caches
- Cargo registry and Git caches
- sccache
Caches are opt-in: OPENCODE_CACHE accepts false (the default, none), all,
or space-separated ids (go, node, python, rust). Setting it also
selects the matching base image variant, so you only pull the layers you
actually use.
Toolchain cache paths are configured with environment variables, letting you move them wherever you have room — for example onto a USB drive:
OPENCODE_PIP_CACHE_DIR=/mnt/usb2/storage/opencode/cache/pip
OPENCODE_SCCACHE_DIR=/mnt/usb2/storage/opencode/cache/rust/sccache
OpenCode’s own config, data and cache live on the host under three roots
(OPENCODE_CONFIG_ROOT, OPENCODE_DATA_ROOT, OPENCODE_CACHE_ROOT), with a
per-project directory created under each automatically at launch. The first
launch of a project seeds its config from a template you control; later
launches leave your changes alone.
That means you can keep the reproducibility benefits of containers without throwing away your development caches every time a container is restarted.
Choose the image variant that fits your project
The base image devsnowdon/opencode-docker is prebuilt and published in three variants:
- empty — minimal CLI toolset
- duck — adds Node.js and Python
- full — adds Go, C and Rust
Each variant is published for v1 and v2 image versions, so you can pick both the toolchain depth and the OpenCode generation you want:
OPENCODE_IMAGE_URL="devsnowdon/opencode-docker:full-v1" opencode
Your workspace image builds on top of the base, so you can pick a variant with
OPENCODE_IMAGE_URL and layer your own tooling on top when you need to.
Built with low powered ARM devices in mind
One particularly interesting aspect of opencode-docker is its focus on ARM devices, including systems such as the Raspberry Pi, while also supporting x86 architectures.
Images are published for linux/amd64 and linux/arm64, and you can also
pin CPU resources when running on constrained hardware:
OPENCODE_CPUSET="2-3" OPENCODE_CPUS="2" opencode
If you’re running AI-assisted development workloads on a home server, ARM machine, Raspberry Pi, or a traditional x86 development computer, this makes the workflow much more flexible.
Simple commands for managing your OpenCode environment
Rather than manually typing long Docker Compose commands, opencode-docker
includes a launcher with convenient commands for common operations. Every
command has its own help (opencode:help <command>) and a short alias.
A taste of the command set:
opencode # (re)create the container and attach a TUI
opencode:up # start the container in the background
opencode:down # remove this project's containers, networks, volumes
opencode:stop # stop managed containers
opencode:ls # list managed containers, ps-style
opencode:exec sh # run a command in the running container
opencode:shell # exec sh
opencode:run npm install # run a task in the service
opencode:repl # interactive bash shell bound to the workspace
One-off agent tasks and planning flows are first-class:
# run a one-off task against an existing project
opencode:bg ./ "refactor this module"
# analyse the branch changes and propose a plan first
opencode:changes "identify issues in these changes"
# plan with the workspace read-only, only the output file writable
opencode:changes --output /tmp/plan.md
opencode:io --output /tmp/out.md < /tmp/create-task-plan.md
And initialize a project before starting OpenCode:
opencode:setup sh -c 'cd front-end && npm install' && opencode
Directory options let you target exactly what you mean — --all, --other,
--this, --dry-run and more apply across stop, delete, ls and down,
and every command accepts a workspace path:
opencode /home/other/somerepo
opencode:exec /home/other/somerepo sh
opencode:down /home/other/somerepo
The project also provides an Oh My Zsh plugin with one alias per command
(oc, ocu, ocd, ocs, ocsh, ocr, occh, ocsf, ocbg, ocio, and
more). The plugin is deliberately lightweight — you are encouraged to build
your own profile or environment with whichever shell you prefer.
For developers who regularly work from the terminal, these helpers make the container workflow feel much closer to using a native command-line tool.
Keep multiple projects isolated
AI-assisted development often means jumping between projects. Each project may have different dependencies, caches, configuration, and runtime requirements.
opencode-docker treats each workspace — and each git worktree — as its own isolated environment, with its own containers, its own Docker network, and its own config, data and cache directories on the host.
Network isolation is configurable through OPENCODE_NETWORK:
- Unset (default) — Docker’s default bridge network.
@default(recommended) — a dedicated bridge network created for this workspace on first use and reused across restarts.- Named network — any existing Docker network, shared between workspaces or external services.
Scaffolding helpers create and initialize new projects with additional task context:
opencode:scaffold path "Create a basic hello world project"
For longer prompts, tasks can also be passed through standard input instead of exposing large arguments directly on the command line.
Worktrees as first-class workspaces
Git worktrees are a natural fit for running several agents side by side, and
opencode-docker treats them as first-class workspaces. A worktree’s .git is a
file pointing into the parent repository, which the launcher mounts read-only —
git stays usable inside the container while the worktree stays isolated.
Commands that hand work to the agent (opencode, run, scaffold, bg) sync
the worktree with its parent branch first: a clean worktree whose parent is
ahead is fast-forwarded, otherwise the launcher reports the divergence and
stops.
For dedicated agent worktrees, opencode:create --worktree creates one per
branch under SD_AGENT_TREE_ROOT, and opencode:uptree starts a container for
one:
mkdir -p "$SD_AGENT_TREE_ROOT" # once, it is not created for you
cd ~/repos/myproject
opencode:create --worktree # the canonical <project>-dev worktree
opencode:uptree "$PWD" # start its container
# or a branch of your own choosing
opencode:create --worktree feature/my-branch
opencode:uptree --branch feature/my-branch "$PWD"
Each worktree is its own workspace with its own container, named after the project and branch, so a project can hold several agent worktrees side by side.
Make it your own
The base images are prebuilt, but nothing stops you from going deeper: extend
the environment with your own Dockerfile (opencode:create --dockerfile
sets that up) and shape the launcher’s configuration to fit your setup.
The images themselves use pinned versions for their tooling and dependencies, and are refreshed with new OpenCode releases on a weekly, best-effort basis.
Getting started
See the README on GitHub for installation instructions, the environment variable reference, the security model, and the full command list.
Who is opencode-docker for?
opencode-docker is especially worth considering if you:
- Use OpenCode regularly
- Prefer containerized development environments
- Want more separation between AI tooling and your host system
- Work across multiple projects, worktrees or agents
- Run read-only planning or review tasks against a workspace
- Use ARM hardware such as Raspberry Pi
- Need persistent caches for multiple language ecosystems
- Want reproducible development environments
- Care about keeping API keys out of container environments
- Spend most of your development time in the terminal
- Use Docker Compose and Oh My Zsh
Give it a try
AI coding tools are becoming an increasingly important part of the modern developer workflow. But convenience shouldn’t mean giving up control over your development environment.
opencode-docker offers a practical approach: run OpenCode inside a
Docker-based environment, mount the projects you want to work on, persist the
caches you need, keep .git history read-only, isolate each workspace on its
own network, and manage everything through straightforward terminal commands.
If you’re looking for a more portable, configurable, and security-conscious way to run OpenCode, check out the project:
github.com/snowdon-dev/opencode-docker
The project is open source and licensed under GPL-3.0-or-later.
Have you been running AI coding agents directly on your host machine, or have you moved toward containers and isolated development environments? opencode-docker is an interesting option for developers who want the power of AI-assisted coding with more control over where that work happens.