Skip to content

Permissions

.config/opencode/opencode.jsonc re-creates the Claude Code sandbox as closely as OpenCode's permission schema allows. It is the OpenCode counterpart to the Claude Code sandbox — same intent (let the agent roam the dev tree, keep it out of credentials), expressed in a different config language.

Why a permission mirror, not a sandbox

OpenCode does not currently accept Claude Code's native sandbox block in opencode.jsonc; unknown top-level keys make OpenCode fail config validation. So instead of a kernel-enforced boundary, the config leans on OpenCode's supported permission schema to approximate the same allow/deny shape.

The mapping follows the sandbox in .claude/settings.json:

Claude Code setting OpenCode mapping
filesystem.allowRead permission.external_directory allow rules for ~/Repos, ~/.config,
~/.cache, ~/.local/runtime, ~/.local/share, ~/.npm, /opt/homebrew,
and /tmp.
filesystem.allowWrite permission.edit prompts for repo/tool cache writes and allows scratch or
agent-worktree writes.
filesystem.denyRead permission.read, permission.list, permission.glob, permission.edit,
and permission.external_directory deny ~/.aws, ~/.config/gcloud,
~/.ssh, ~/.gnupg, and dotenv files.
Claude permissions.allow Bash permission.bash pre-approves the same inspection, Homebrew, Git, and
allowlist commit-script chmod patterns, then adds final deny patterns for credential
and dotenv paths.
Claude WebSearch allow permission.websearch = "allow"; webfetch still prompts.

Ordering and the catch-all

OpenCode permission objects use last-match-wins ordering, so the config keeps broad rules first and narrower allow/deny rules later — the credential and dotenv denies sit at the end of each block so nothing earlier can re-open them. The top-level "*": "ask" flips OpenCode's permissive default: any tool or command that isn't explicitly mapped requires approval.

grep is allowed for routine searches even though OpenCode matches grep permissions against the searched regex, not the target path. The path boundaries therefore stay on read, list, glob, edit, and external_directory, which do match against paths.

Limits

This is a permission-layer approximation, not the kernel-enforced boundary Claude Code runs. Claude's network.allowedDomains, allowMachLookup, allowUnixSockets, and allowUnsandboxedCommands fields have no OpenCode config equivalent today. Network-capable Bash commands are therefore controlled by the permission.bash allowlist and approval prompts rather than by domain-level egress rules.

See opencode.jsonc for the full rule set. After changing it, quit and restart OpenCode — config is loaded at startup.