opencode-sandbox is an OpenCode plugin that runs every bash command an agent executes inside an operating-system sandbox, built on the @anthropic-ai/sandbox-runtime engine. No containers or virtual machines are involved: macOS uses sandbox-exec Seatbelt profiles and Linux uses bubblewrap namespace isolation. Windows commands pass through unsandboxed, because OpenCode currently exposes the hook as a command string while the runtime's Windows support takes an argv-and-environment interface.
Three restrictions apply to a sandboxed command. Writes are limited to the project directory, the validated git worktree, and /tmp, and anything else reports a read-only file system. Reads of credential locations such as ~/.ssh, ~/.gnupg, ~/.aws/credentials, ~/.config/gcloud, ~/.npmrc, and ~/.env are denied. Network traffic goes through a local proxy that allows only listed domains — package registries, GitHub, GitLab, the OpenAI and Anthropic APIs, and googleapis.com by default — and blocks everything else.
Configuration is resolved from the OPENCODESANDBOXCONFIG environment variable, then a per-project file, then a global file, then built-in defaults. The files live under ~/.config/opencode-sandbox/ outside the project, so a sandboxed command cannot weaken the sandbox by rewriting them through indirect prompt injection. Path precedence follows the underlying runtime: allowRead beats denyRead, and denyWrite beats allowWrite, which is what lets a single public key be re-allowed while the rest of ~/.ssh stays blocked.
The plugin uses two hooks — tool.execute.before wraps the command, and tool.execute.after restores the original text in the interface. Sandbox initialisation is deferred until the first bash command so startup is untouched, diagnostics go to OpenCode's structured logger rather than the terminal interface, and violations are correlated with each individual tool call, including concurrent or repeated commands. The model reads sandbox errors straight from command output. If initialisation or wrapping fails, or the platform is unsupported, the command runs without a sandbox.
Features
- Per-command wrapping: every bash tool invocation is wrapped with filesystem and network restrictions
- Native isolation: sandbox-exec Seatbelt profiles on macOS, bubblewrap namespaces on Linux
- Write containment: writes are limited to the project directory, the validated worktree, and /tmp
- Credential blocking: reads of SSH, GPG, cloud, npm, and env credential paths are denied by default
- Network allowlist: a local proxy permits listed domains only and blocks all other traffic
- Injection-resistant config: configuration lives outside the project so sandboxed commands cannot rewrite it
- Layered configuration: an environment variable, a per-project file, a global file, then built-in defaults
- Deferred init: the sandbox starts on the first bash command rather than at OpenCode startup
- Fail-open design: if the sandbox cannot be set up, commands run normally instead of failing
