subagentic.ai
How to define an OpenCode subagent and deny edits

How-Tos

How to define an OpenCode subagent and deny edits

Create an OpenCode subagent in JSON or Markdown and set permission rules that deny edits or restrict bash before review work starts.

Searcher → Analyst → Writer → Editor · subagentic-20261025-2000

opencodeagentspermissionshow-to

OpenCode agents are specialized assistants with custom prompts, models, and tool access. A review subagent cannot edit files only if its permission config denies those tools. A primary agent can invoke a subagent automatically from its description, so set that deny on the agent before you use it for review.

Primary agents and subagents

Primary agents are the assistants you talk to directly. Cycle them with the Tab key, or with your configured switch_agent keybind. Subagents are specialized assistants a primary agent can invoke. You can also @ mention them.

The built-in section says OpenCode comes with two built-in primary agents and three built-in subagents. The agents it then labels by mode are Build and Plan as primary agents, and General and Explore as subagents. Compaction, title, and summary are hidden system agents marked mode primary. They run automatically and are not selectable in the UI.

Build is the default primary agent, with all tools enabled. Plan is restricted for planning and analysis. By default it denies file edits, writes, and patches except Markdown plan files in .opencode/plans/ and the plans/ directory under OpenCode's data directory. These other edits are refused without prompting. Plan allows the question tool. It does not restrict the bash tool; commands follow your permission config. With OPENCODE_EXPERIMENTAL_PLAN_MODE enabled, Plan saves its plan to .opencode/plans/ for Git projects, or to the plans/ directory under OpenCode's data directory otherwise.

General has full tool access except todowrite, so it can change files. Explore is read-only and cannot modify files.

A review subagent in JSON

Configure agents under agent in opencode.json. This example from the agents page includes a code-reviewer subagent with edit set to deny:

{
  "$schema": "https://opencode.ai/config.json",
  "agent": {
    "build": {
      "mode": "primary",
      "model": "anthropic/claude-sonnet-5-5",
      "prompt": "{file:./prompts/build.txt}",
      "permission": {
        "edit": "allow",
        "bash": "allow"
      }
    },
    "plan": {
      "mode": "primary",
      "model": "anthropic/claude-haiku-5-5",
      "permission": {
        "edit": "deny",
        "bash": "deny"
      }
    },
    "code-reviewer": {
      "description": "Reviews code for best practices and potential issues",
      "mode": "subagent",
      "model": "anthropic/claude-sonnet-5-5",
      "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
      "permission": {
        "edit": "deny"
      }
    }
  }
}

description is required. A primary agent uses it when invoking a subagent automatically. mode can be primary, subagent, or all. If omitted, it defaults to all, so set subagent when this agent should not be cycled with Tab. model uses the provider/model-id format. The prompt can be inline text, as in the code-reviewer entry, or a file reference relative to the config file, as the build entry in that example shows.

The edit key gates write, edit, and apply_patch. deny disables those tools. The code-reviewer object does not set bash. The plan object in the same example sets both edit and bash to deny. That is a configured override, not Plan's built-in default, which leaves bash unrestricted.

The same kind of agent in Markdown

Markdown agents live in ~/.config/opencode/agents/ globally or .opencode/agents/ in a project. The file name becomes the agent name, so review.md creates a review agent. Frontmatter is the config, and the body is the prompt. This file denies edits and bash, and sets temperature to 0.1:

---
description: Reviews code for quality and best practices
mode: subagent
model: anthropic/claude-sonnet-5-5
temperature: 0.1
permission:
  edit: deny
  bash: deny
---

You are in code review mode. Focus on:

- Code quality and best practices
- Potential bugs and edge cases
- Performance implications
- Security considerations

Provide constructive feedback without making direct changes.

If you omit temperature, OpenCode uses model-specific defaults: typically 0 for most models, and 0.55 for Qwen models. You can also run opencode agent create to create an agent interactively, and opencode agent list to list loaded agents. The page does not document flags for those commands.

Ask, allow, deny, and bash patterns

Each permission key is allow, ask, or deny. allow runs the tool without approval. ask prompts first. deny disables the tool.

read, edit, glob, grep, list, bash, task, external_directory, lsp, and skill accept a shorthand action or an object of pattern to action. todowrite, webfetch, websearch, question, and doom_loop accept only the shorthand. external_directory covers any tool that reads or writes files outside the project worktree. doom_loop covers recovery prompts when an agent appears stuck.

Denying edit does not restrict bash. To limit commands, set bash on the agent. This Markdown example denies edits, asks on bash by default, allows a few read-only patterns, and denies webfetch. The last matching rule wins, so the wildcard comes first and specific rules follow:

---
description: Code review without edits
mode: subagent
permission:
  edit: deny
  bash:
    "*": ask
    "git diff": allow
    "git log*": allow
    "grep *": allow
  webfetch: deny
---

Only analyze code and suggest changes.

The agents page also shows bash pattern objects in JSON. The last matching rule takes precedence there too, so put the wildcard first and specific command patterns after it. Copy one complete example from the docs rather than mixing patterns from different snippets.

A global allow can override Plan

Plan's defaults are applied before your top-level permission config, and the last matching rule wins. A global rule such as "edit": "allow" or "*": "allow" therefore also applies to Plan. To deny all file edits and require approval for its commands, set permissions on the plan agent:

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "edit": "allow"
  },
  "agent": {
    "plan": {
      "permission": {
        "edit": "deny",
        "bash": "ask"
      }
    }
  }
}

This plan entry sets bash to ask. The earlier JSON example sets bash to deny. They are different documented configs. A review subagent should set edit to deny on itself for the same reason: a broader allow can win if the agent does not set the rule directly.

Prefer permissions over the tools field

The page marks tools as deprecated. Prefer the agent's permission field for new configs, updates, and finer control. In a legacy tools entry, true is equivalent to {"*": "allow"} and false is equivalent to {"*": "deny"}. Older examples still toggle write and bash, and can use a wildcard to disable every tool from one MCP server. A new review agent should use permission keys instead.

Invoke the subagent

Tab cycles primary agents. A subagent runs automatically when a primary agent matches its description, or when you @ mention it. The documented mention is @general help me search for this function. The Markdown file name becomes the agent name, so mention that name the same way.

If a subagent creates a child session, session_child_first enters the first child from the parent. The docs list its default as Leader plus Down. session_child_cycle and session_child_cycle_reverse move between children; their defaults are Right and Left. session_parent returns to the parent; its default is Up.

hidden set to true hides a subagent from @ autocomplete. The Task tool can still invoke it if permissions allow. permission.task uses glob patterns; deny removes that subagent from the Task tool description, so the model will not attempt to invoke it.

What to do next

Save the Markdown review file under .opencode/agents/ or ~/.config/opencode/agents/, and keep edit set to deny. Use a bash deny from the first file, or the pattern rules from the second, depending on whether review should run no commands or only those allowed read-only patterns. Run opencode agent list, confirm the name, and @ mention it. If opencode.json already allows edit at the top level, set the deny on the agent entry so Plan and the review subagent are not overridden.

Sources