Note: This is a personal project configured for my use case that I made public in case anybody else finds it useful. You will need to edit the Dockerfile (and the languages/tools baked into the image) to match your setup.
A single self-contained folder that wraps opencode in an isolated rootless podman container, so the AI coding agent can only see the current project folder and its own shared config.
No per-project scaffolding. No docker-compose. No extra users to create.
Build the image once, then cd into any project and run opencode-sbx.
podman. The wrapper is designed for rootless podman; running it with rootful podman will likely create files owned by root on the host. Verify rootless podman works withpodman info(no root needed).bashon the host.
# from anywhere
opencode-sbx setup # builds localhost/opencode-sbx:latest
# one-time: add the folder to PATH (the installer doesn't do this for you)
echo 'export PATH="$PATH:/work/opencode-sbx"' >> ~/.bashrc
# then `source ~/.bashrc` or open a new shellThe build bakes in your host UID/GID so files created inside the container
are owned by you on the host. If your UID/GID ever changes, rerun setup.
cd /any/project
opencode-sbx # opens opencode against the current folder
opencode-sbx -- uname -r # run a one-off command inside the container
opencode-sbx verify # show isolation stateOpencode configuration, credentials (auth.json from /connect), sessions,
snapshots, and runtime state are shared across all projects at three
host-side dirs:
${XDG_CONFIG_HOME:-~/.config}/opencode-sbx/— opencode config (opencode.json, agents, etc.)${XDG_DATA_HOME:-~/.local/share}/opencode-sbx/— auth, sessions, snapshots${XDG_STATE_HOME:-~/.local/state}/opencode-sbx/— model history, prompt history, and other runtime state
All three respect the standard XDG_CONFIG_HOME / XDG_DATA_HOME /
XDG_STATE_HOME env vars (default to ~/.config / ~/.local/share /
~/.local/state when unset).
Only the project source tree ($PWD → /work) is per-project. Configure
providers once via /connect and every project picks them up.
| Variable | Default | Purpose |
|---|---|---|
OPENCODE_SBX_CPUS |
4 |
Container CPU quota |
OPENCODE_SBX_RAM |
4g |
Container memory limit |
Example: OPENCODE_SBX_CPUS=2 OPENCODE_SBX_RAM=2g opencode-sbx
Alpine Linux edge with: opencode (installed at build time via the
official installer — no curl|bash at runtime), git, nodejs, npm,
python3, py3-pip, .NET SDK (latest LTS via the dot.net install script —
invariant globalization, telemetry opted out), rust/cargo/rustfmt/
clippy (via rustup — latest stable, --no-modify-path), make, gcc,
musl-dev, gcompat, vim, openssh-client. Edit Dockerfile and run
opencode-sbx rebuild to tweak. Rebuild pulls latest opencode, latest stable
Rust, and latest .NET LTS.
Ultimately, this is just a plain rootless podman container so ensure it fits your security model.
Three namespaces isolate the agent from your host:
- Mount namespace — only
$PWD(at/work) and the shared opencode config/data/state dirs are visible. Your~/.ssh,~/.aws, other projects,/etc/shadow— none are mounted in. Opencode state (config, auth, sessions, snapshots, model history) is shared across all projects by design; only the project source tree differs per run. - User namespace — container UID
0maps to your host UID only, not host root. With--userns=keep-id --user UID:GID, the agent runs as a non-root user inside the container. - Network namespace — rootless NAT; the container can reach the network (so opencode can call the model API) but is not a peer on your host LAN.
Important caveat: the container shares the host kernel. A container escape via a host-kernel privilege-escalation bug would land the attacker as your host user in one step. There is no separate guest-kernel barrier.
In practice this is a reasonable sandbox for an AI coding agent you are spot-checking. For genuinely untrusted code (which can include AI-generated code), use a full VM instead.
The $PWD (host project) mount uses :z only — it is not recursively
chowned. If files in your project dir are owned by another host user, the
agent may see permission errors. The shared opencode config/data/state dirs
are chowned to the container user.
| File | Purpose |
|---|---|
opencode-sbx |
Wrapper script (executable, add folder to PATH) |
Dockerfile |
Alpine image definition |
entrypoint.sh |
Execs CMD (opencode is baked in at build time) |
README.md |
This file |
| Command | What it does |
|---|---|
opencode-sbx |
Launch opencode in $PWD |
opencode-sbx -- <cmd>... |
One-off command inside the container |
opencode-sbx setup |
Build the image (run once) |
opencode-sbx build |
Same as setup |
opencode-sbx rebuild |
Rebuild image (no cache) |
opencode-sbx verify |
Show UID, mounts, isolation caveat |
opencode-sbx help |
Usage message |