opencode agents: setting up roles, models and tools

A custom agent in opencode is a role, a model and a set of permissions. A working config where a cheap model handles routine work and a stronger one edits code.

5 min · · агенты · экономия

By default opencode works as one general-purpose assistant that can do everything: read, edit files, run commands. That is convenient until you notice that writing a commit message burns the same expensive model as a hard refactor. Here we cover how opencode agents are structured, how to define your own, and how to hand it only the permissions it needs.

The parameters were checked against the Agents section of the opencode.ai/docs documentation as of October 18, 2026. The project carries a note about a second version, so if your version behaves differently, open the documentation for that version.

Which agents opencode has

Agents come in two types.

Primary agents are the ones you talk to. You switch between them with Tab. Two are built in: Build (all tools enabled) and Plan (restricted: edits and bash require approval by default, and it is meant for analysis and plans).

Subagents are helpers that a primary agent calls for a separate task, or that you call with an @name mention. Built in: General (general purpose, can edit files), Explore (fast, read-only) and Scout (read-only, for external docs and dependency sources).

There are also hidden system agents: one compacts long context, another generates session titles, a third produces summaries. You cannot pick them in the UI, but they also call a model. More on that in the cost section below.

Two ways to define an agent

The first is the agent block in opencode.json. The key is the agent name:

bash
{
  "$schema": "https://opencode.ai/config.json",
  "agent": {
    "reviewer": {
      "description": "Code review without edits",
      "mode": "subagent",
      "model": "anthropic/claude-opus-5-5",
      "prompt": "You are a reviewer. Look at security, performance and readability.",
      "permission": { "edit": "deny" }
    }
  }
}

The second is a markdown file. Put it in ~/.config/opencode/agents/ (all projects) or .opencode/agents/ (the current one). The file name becomes the agent name: review.md creates an agent called review. Settings go in the front matter, and the text after it is the system prompt.

The description field is required. Without a description the primary agent will not know when to call that subagent.

A quick way to scaffold one is opencode agent create: it asks where to save it and what the agent is for, then lets you pick permissions, denying everything you do not select.

What you can set

  • model in provider/model format. If omitted, a primary agent uses the global model, and a subagent uses the model of the primary agent that called it.
  • permission is what the agent may do: read, edit, bash, task, webfetch and others. Values are allow, ask, deny; for edit and bash you can pass an object with patterns.
  • mode is primary, subagent or all (the default).
  • steps caps the number of agent steps. At the limit the agent must wrap up with a text answer. It is a simple guard against expensive loops.
  • temperature, top_p control randomness. If unset, model defaults apply.
  • prompt is text or a file via {file:./prompts/review.txt}, with the path relative to the config location.
  • hidden hides a subagent from the @ suggestions (subagents only).

The tools field is marked deprecated in the docs; for new configs they recommend permission.

Example: a cheap model for routine work

Say claude-sonnet-5 does the main work, claude-opus-5-5 builds plans, and commit messages and docs edits go to an inexpensive model. For Claude we use the built-in anthropic provider (so the gateway sees the cache), and for cheap models we add an OpenAI-compatible provider. The address in both cases is https://api.zukko.pro/v1; details are in the opencode documentation.

bash
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-5",
  "small_model": "zukko/glm-5.3-flash",
  "provider": {
    "anthropic": {
      "options": { "baseURL": "https://api.zukko.pro/v1", "apiKey": "{env:ZUKKO_API_KEY}" },
      "models": { "claude-sonnet-5": {}, "claude-opus-5-5": {} }
    },
    "zukko": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Zukko",
      "options": { "baseURL": "https://api.zukko.pro/v1", "apiKey": "{env:ZUKKO_API_KEY}" },
      "models": {

The docs describe small_model as a separate model for lightweight tasks such as session titles. If unset, opencode tries to find something cheaper at your provider, otherwise it uses the main model. Better to set it explicitly so you are not guessing where those requests go.

Now the file .opencode/agents/changelog.md:

bash
---
description: Writes commit messages and CHANGELOG entries from git diff
mode: subagent
model: zukko/deepseek-v4.1-flash
temperature: 0.2
steps: 8
permission:
  edit:
    "*": deny
    "CHANGELOG.md": allow
  bash:
    "*": deny
    "git diff*": allow
    "git log*": allow
    "git status*": allow
---
You maintain the change history. Read the diff, group changes by meaning
and write briefly, in past tense. Do not invent anything that is not in the diff.
Edit only CHANGELOG.md.

In permission rules the last matching rule wins, so the blanket "*": deny comes first and the exceptions after it. Swap the order and the deny overrides the allows.

Using the agent is simple: write @changelog prepare an entry for the last three commits. The primary agent can also call it on its own, guided by description.

Limiting who an agent can call

An orchestrator has the task permission. With it you can list which subagents it may invoke:

bash
{
  "agent": {
    "orchestrator": {
      "mode": "primary",
      "permission": {
        "task": { "*": "deny", "changelog": "allow", "reviewer": "ask" }
      }
    }
  }
}

A denied subagent disappears from the tool description, so the model does not even try to call it. You can still call any of them manually through @.

What it saves

Zukko prices on October 18, 2026, $ per 1M tokens, cache ignored. An illustrative routine agent run: 50,000 input tokens and 5,000 output tokens.

  • deepseek-v4.1-flash (0.013 input / 0.038 output): 0.05 × 0.013 + 0.005 × 0.038 = 0.00065 + 0.00019 = $0.00084.
  • claude-sonnet-5 (0.4 / 2): 0.05 × 0.4 + 0.005 × 2 = 0.02 + 0.01 = $0.03.

Over a hundred runs that is about $0.08 versus $3.00. The gap matters when routine work happens every day. But do not hand everything to a cheap model: it will not always be enough for commits and docs, so test it on your own tasks. Current prices and the model list are in GET https://api.zukko.pro/v1/models.

Checking it

  1. Start opencode and run /models: models from both providers should be listed.
  2. Call @changelog and confirm it cannot edit anything except CHANGELOG.md.
  3. Look at the "Usage" section in the Zukko dashboard: requests should go to the model you assigned to the agent.

Create a separate key with a daily limit for the agent: then a looping agent hits the limit rather than your whole balance. You can make one on the API keys page.

FAQ

How is an agent different from a subagent?

You use a primary agent directly, switching with Tab. A subagent is called by a primary agent or by you via @, and it performs a separate task in its own session.

How do I connect MCP to just one agent?

Servers are declared in the mcp block, and access to their tools is limited with permissions or patterns like server_name_*. Details and examples are in the MCP servers section of the opencode docs.

How is this similar to agents in Cline?

The idea is shared: a role, a set of allowed actions and its own model. The settings differ between tools, so a config does not carry over from one to the other. Check each tool's documentation.

The agent does not see the model from my config. What now?

Check that the model name in agent.<name>.model matches the key in the provider's models block and that the provider is right: zukko/deepseek-v4.1-flash, not just deepseek-v4.1-flash.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

opencode agents: set up roles, models and permissions · Zukko