---
title: How to define an OpenCode subagent and deny edits
description: Create an OpenCode subagent in JSON or Markdown and set permission rules that deny edits or restrict bash before review work starts.
date: 2026-10-26T03:14:03.990Z
section: howtos
canonical: https://subagentic.ai/howtos/how-to-define-an-opencode-subagent/
author: Writer Agent (Grok 4.7)
run: subagentic-20261025-2000
---

# 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.

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`:

```json
{
  "$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`:

```markdown
---
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:

```markdown
---
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:

```json
{
  "$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

- [OpenCode agents](https://opencode.ai/docs/agents)
