Course · OpenCode · Permissions & isolation
Permissions & isolation
Every coding-agent session carries a leash question: how much can it do without asking? On feedmill - the course’s illustrative Go feed aggregator, a Go CLI plus a sync server pulling RSS, Atom, and JSON feeds into one reading queue - the answer depends entirely on which part of the repo the agent is about to touch. The reading store is the one part of the project that isn’t trivially regenerable: mangle it and the only recovery is re-pulling every source, some of whose older entries no longer exist at the feed. A throwaway script for probing one flaky source is the opposite pole: nothing it can break is worth protecting, and a prompt before every command is pure tax. Handing both jobs the same amount of trust is wrong in both directions - too loose near the store, too fussy on the scratch script. This chapter is about making the leash fit the job, and it matters more the more agents you run: every subagent a delegation fans out (a helper agent the main agent hands a task to, in its own session) is another agent touching the same filesystem, and each one arrives with its own leash.
OpenCode’s permission model is built for exactly this. Permissions are per-tool per-agent: each agent - a named preset of prompt, model, and permissions you switch between, such as OpenCode’s built-in build and plan or any agent you define - carries its own map of what edit, bash, read, and the other tools may do, with three values per tool: allow it to run silently, ask you before every use, or deny it outright. You can go finer than a whole tool, gating bash down to specific command patterns and edit or read down to file path patterns, so the store can have rules of its own (permissions documentation, as of October 2026). So “let it read anything but ask before every edit, and never let it run git push” isn’t a reflex you maintain by hand; it’s a policy you write down once. Until you write it, the policy is permissive: out of the box the built-in build agent edits files and runs bash without asking, and only doom_loop, external_directory, and a read rule for .env files stop it by default (agent.ts, as of October 2026, v1.18.32). Deciding that boundary deliberately, per job - what the agent may do without asking, and where it must stop for you - is the control principle at work, and this chapter is its natural home in the course.
One boundary fact to hold onto before anything else, because every page here stands on it: OpenCode’s permissions documentation (as of October 2026) describes a tool-policy layer - rules that gate the tools OpenCode itself invokes, edit, bash, read, external_directory (tool calls that touch paths outside the directory where OpenCode started), and the rest. It does not document an OS-level sandbox: an approved bash command still runs as your user, on your machine, with your credentials. When a job needs that stronger boundary - walling the process off from the files and network it shouldn’t touch - the move is to run the whole CLI inside a container or another sandbox you control; Docker, for one, documents a sandbox path for OpenCode as of September 2026. Policy decides what the tools may do; a container decides what the process may reach.
The chapter’s pages, in reading order:
- Set permissions per tool, per agent - write the policy map that lets reads and searches run free while
editandbashstop and ask, then tightenbashto exactly the commands you trust near the reading store. This is also where the shipped defaults live, including the.envread rule and the two keys that ask by default. - Switch agents to switch policy - because the map rides on the agent, picking an agent is picking a posture:
planfor the no-edits middle (it leaves bash ungated unless you add a rule),buildfor the free hand, and a customauditagent for a hard read-only wall. In OpenCode a saved posture is an agent: per-agent policy is the first-class knob. - Isolate by running in a container - face the sharp edge honestly: permissions gate OpenCode’s tools, not your OS, so for real isolation you put the CLI in a container - which is exactly where OpenCode being just-a-CLI pays off.
Do these as one continuous stretch on feedmill and a single idea threads through all three: the unit of trust in OpenCode is the agent. Permissions are properties of an agent, switching agents switches the agent-level rules layered over your global config, and the one thing permissions can’t do - wall the agent off from your machine - is handled one layer out, by changing where the agent runs rather than what it’s allowed to call. That last move is also the foundation for unattended work: the sharing and headless chapter puts OpenCode in CI, where nobody sits at the keyboard to answer an ask, and the container it uses there is the same box this chapter builds.