opencode-sandbox launches opencode inside a small Bubblewrap sandbox for Linux.
It is a small Bash wrapper that:
- uses the current directory as the writable project root,
- stores sandbox state under
./.sandbox, - keeps host network access enabled,
- uses a private in-sandbox server for OpenCode V2 clients,
- and mounts Node automatically when the resolved
opencodeentrypoint is a Node launcher.
Running opencode in a sandbox gives it the files it needs for the current project without giving it unrestricted access to the rest of the machine.
This wrapper is useful when you want to:
- avoid accidental reads or writes outside the repo,
- keep generated state in
./.sandbox, - reduce the impact of bad commands, broken scripts, or prompt mistakes,
- and make the environment more predictable across Linux machines.
The goal is not perfect isolation. It is a practical safety boundary that keeps day-to-day usage pointed at the project directory instead of the whole host system.
- Linux, including WSL
- Bubblewrap must be installed; check with
command -v bwrap - OpenCode V1 or V2 required
Non-Linux platforms are out of scope for this version.
curl -fsSL https://raw.githubusercontent.com/ribomo/opencode-sandbox/main/install.sh | bashOr with a custom install directory:
curl -fsSL https://raw.githubusercontent.com/ribomo/opencode-sandbox/main/install.sh | PREFIX=/usr/local/bin bashThen run it from any project:
opencode-sandboxRun the wrapper from the project directory you want to expose inside the sandbox:
opencode-sandboxRun a simple launch check:
opencode-sandbox --helpThe wrapper creates generated state in .sandbox/. Add this directory to your
project's .gitignore:
.sandbox/If it is not ignored, sandbox state can be included recursively and the directory will grow on each run.
Pass any normal Opencode arguments through the wrapper:
opencode-sandbox --help
opencode-sandbox run "summarize this repository"
opencode-sandbox api get /api/infoUpdate OpenCode outside the sandbox so the updater can write to the host installation:
-
Exit the sandbox session.
-
In a normal host terminal, run:
opencode update
-
Start
opencode-sandboxagain to use the updated version.
The OpenCode installation is normally mounted read-only inside the sandbox,
so in-session updates cannot replace the host executable. The wrapper currently
also runs opencode-sandbox update and opencode-sandbox upgrade inside
Bubblewrap; automatic host-side forwarding for these commands is not yet
implemented. Use the host command above until that shortcut is available.
V2 normally discovers or starts a detached background service. That service
owns tool execution, and its lifecycle does not fit the sandbox's PID namespace.
The wrapper automatically adds --standalone to supported client commands,
including the TUI, run, mini, and api, so their private server runs inside
the sandbox and exits with the client. The wrapper checks the installed version
and identifies supported V2 client commands directly. V1 arguments are passed
through unchanged. If the version cannot be identified, arguments are also
passed through unchanged.
Explicit --standalone or --server arguments are passed through. When using
--server, tools execute on that server; this wrapper only sandboxes the local
client. Service-management commands are passed through as well; a detached
service is not intended to persist after the sandbox exits.
- The current working directory is bind-mounted read-write.
- Sandbox state is written to
./.sandbox. /usr,/etc, and common system library directories are mounted read-only./runis mounted read-only so host runtime files such as DNS resolver state remain available./mnt/wslis mounted read-only when present so WSL's/etc/resolv.confsymlink can resolve to/mnt/wsl/resolv.conffor DNS.- The wrapper always shares the host network namespace.
- If the resolved Opencode entrypoint starts with a Node shebang, the wrapper also exposes the matching Node install root.
XDG_CONFIG_HOMEpoints to./.sandbox/config. When host OpenCode configuration exists, it is mounted at./.sandbox/config/opencode/read-only; otherwise, OpenCode uses writable sandbox-local configuration.
If ~/.config/opencode/ (or $XDG_CONFIG_HOME/opencode/) exists, it is
bind-mounted read-only at ./.sandbox/config/opencode/. OpenCode reads your
host configuration directly; the wrapper does not copy or migrate it. Settings
changes and V2 migration must be performed outside the sandbox.
If there is no host config directory, OpenCode uses the writable sandbox-local config directory instead.
The host OpenCode data directory ($XDG_DATA_HOME/opencode, defaulting to
~/.local/share/opencode) is still mounted read-write when present, sharing
credentials and session history. Cache and state directories remain local to
.sandbox.
Run the wrapper regression checks with Python 3:
python3 -m unittest discover -s tests -v
bash -n opencode-sandbox install.shThe sandbox sets up SSH so that git push, git fetch, and other remote operations work from within the sandbox.
GIT_SSH_COMMANDis set with absolute paths into.sandbox/home/.sshfor SSH config and host keys. The-Fflag skips the host's system SSH config (/etc/ssh/ssh_config), which may have broken ownership or permissions in some container/sandbox environments.- If
~/.ssh/configexists on the host, it is bind-mounted read-only into the sandbox. Otherwise an empty config is created so-Fhas a file to read. - If
~/.ssh/known_hostsexists on the host, it is bind-mounted read-only, preserving host-key verification state across sandbox runs. - If
SSH_AUTH_SOCKis set and points to a valid socket with loaded identities, it is forwarded into the sandbox so existing SSH agent connections work. - If no usable SSH agent is available, the wrapper starts a temporary host-side agent, runs
ssh-addfor the first default key it finds, forwards that agent socket into the sandbox, and stops the temporary agent when Opencode exits. - Private keys such as
id_ed25519,id_ecdsa, andid_rsaare never mounted into the sandbox. If no key can be loaded into an agent, SSH-based Git operations fail safely instead of exposing key material.