Creating agents in OpenCode: where to put them, four complete examples
Agent vs chatbot
A chatbot answers; an agent acts. The difference is the loop: the agent
reads the goal, picks a tool, observes the result, and repeats until the
goal is done or it gets stuck and asks for help. If your system cannot
call tools and see results, it is a chatbot with good marketing.
In OpenCode an agent is a named profile:
system prompt plus model plus permissions plus mode. Reusable task
checklists live in skills and agents load
them on trigger — agents add identity, skills add instructions.
Where to put agents
Same model trio as skills — Muse Spark 1.3 Free, GPT 6 Luna, Claude Opus 5.5 — but here you pin a different model per role. Personal agents go global, team agents go in the repo and get committed.
- Project, recommended: .opencode/agents/<name>.md — nested path becomes id with slash, team/reviewer.md becomes team/reviewer.
- Global, personal: ~/.config/opencode/agents/<name>.md — every project of the user.
- Inline in config: agents map in opencode.jsonc — same fields, body goes to system. Handy for one-line overrides of built-ins.
Built-ins you can override by reusing the id: build (primary coder, default), plan (primary, no project edits), general (subagent research), explore (subagent read-only). Hidden title, summary, compaction do maintenance and cannot be selected. Full tree with links is under Real project skeleton.
How to build an agent
A Markdown agent is frontmatter plus a body. Frontmatter accepts the same fields as the JSON map. The body becomes the system prompt:
--- description: Reviews changes for correctness and regressions mode: subagent model: opencode/claude-opus-5-5 steps: 8 color: "#ff6b6b" permissions: - action: edit resource: "*" effect: deny --- Review the current changes. List findings in severity order.
Fields that matter in practice:
- description: one line shown to the model that picks subagents. Always set it for subagents.
- mode: primary runs as main session, subagent runs only as child via the subagent tool, all runs both ways. New custom agents default to primary.
- model: provider/model plus optional #variant, for example opencode/gpt-6-luna or opencode/claude-opus-5-5. Empty means inherit the parent session model.
- steps: max model steps before tools are removed and a summary is forced. Use 6 to 10 for reviewers, leave empty for builders.
- permissions: ordered allow, ask, deny rules. Last match wins. Common actions: shell, edit, read, glob, grep, webfetch, websearch, skill, subagent.
- color, hidden, disabled: UI color hex, hide from pickers, remove a built-in at that config layer.
JSON form for quick overrides without a file:
{ "$schema": "https://opencode.ai/config.json", "default_agent": "build", "agents": { "build": { "permissions": [ { "action": "shell", "resource": "git push *", "effect": "deny" } ] } } }
Later configs merge: scalars replace, permission rules append, so global allow plus agent deny yields deny. A subagent uses its own permissions, not a subset of the parent. Control which children a parent may launch:
{ "agents": { "orchestrator": { "permissions": [ { "action": "subagent", "resource": "*", "effect": "deny" }, { "action": "subagent", "resource": "reviewer", "effect": "allow" } ] } } }
Real project skeleton
Agent side of the same demo project from Skills skeleton. Output of tree, every element links to the chapter or file where it is explained:
my-app/ ├── opencode.jsonc ├── .opencode/agents/ │ ├── reviewer.md │ ├── builder.md │ ├── triage.md │ └── team/orchestrator.md ├── .opencode/skills/ │ ├── api-review/ │ │ └── SKILL.md │ └── test-writer/ │ └── SKILL.md ├── .opencode/commands/ │ ├── review.md │ └── build-feature.md └── AGENTS.md
Read it as roles: reviewer is the Opus-only read-only judge, builder is the Luna daily driver, triage is the Spark Free inbox sorter, orchestrator fans out to children. Commands select the agent and model in one keystroke. Skills beside them supply the checklists each role loads.
Four complete agents
Four files you can drop into .opencode/agents/ today. They map to the model split from Models that matter: cheap triage, standard build, top review, plus one orchestrator that ties them together. How they share one project with gated skills is shown in Three models, one project.
Example 1 — Opus reviewer, read-only. File .opencode/agents/reviewer.md, id reviewer. Final pass on staged diffs, never edits:
--- description: Final correctness and security pass over staged diffs mode: subagent model: opencode/claude-opus-5-5 steps: 8 permissions: - action: edit resource: "*" effect: deny - action: shell resource: "*" effect: deny - action: skill resource: "*" effect: deny - action: skill resource: api-review effect: allow --- Review the staged diff. Load api-review first. Report bugs first in severity order with file and line. Verdict: ship, fix first, or block. Do not edit files.
Launch with Use the reviewer subagent to review my staged changes. It loads only api-review, so output stays in rubric form even on large diffs.
Example 2 — Luna builder, daily driver. File .opencode/agents/builder.md, id builder. Cheap, steady, allowed to edit and test but never push:
--- description: Implements small features with tests on GPT 6 Luna mode: primary model: opencode/gpt-6-luna permissions: - action: shell resource: "*" effect: ask - action: shell resource: "git status *" effect: allow - action: shell resource: "git diff *" effect: allow - action: shell resource: "npm test *" effect: allow - action: shell resource: "git push *" effect: deny --- Implement the requested change in small steps. After each edit run the narrowest test command and show the diff. Stop after two failing attempts and report what is missing.
Pair with @test-writer for coverage: With builder, add pagination to orders and cover it with test-writer.
Example 3 — Spark Free triage, inbox sorter. File .opencode/agents/triage.md, id triage. Free, fast, capped steps, explains code without changing it:
--- description: Explains code and sorts small tasks without editing mode: primary model: opencode/muse-spark-1.3-contributor-free steps: 6 permissions: - action: edit resource: "*" effect: deny - action: shell resource: "*" effect: deny --- Explain the relevant code with short examples. Sort the request into docs, small fix, or needs-build. Propose the next agent: builder for fixes, plan for features. Do not edit files. Never handle secrets.
Start every morning on triage, escalate only what needs tools: With triage, explain src/auth.ts login flow and route the refresh bug. Keeps free-tier privacy safe because it never touches .env files.
Example 4 — orchestrator that fans out. File .opencode/agents/team/orchestrator.md, id team/orchestrator. Plans on Luna, delegates review to Opus, research to general:
--- description: Plans a feature then fans out to builder and reviewer mode: primary model: opencode/gpt-6-luna permissions: - action: subagent resource: "*" effect: deny - action: subagent resource: "builder" effect: allow - action: subagent resource: "reviewer" effect: allow - action: subagent resource: "explore" effect: allow --- Plan the feature in three bullets: files, schema, tests. Then ask explore to map unknowns and builder to implement step one. Finish by asking reviewer for a verdict. Report the three results.
Launch with With team/orchestrator, plan cursor pagination for orders. The parent stays usable while background children run, results return to the parent session.
Commands that select these agents. File .opencode/commands/review.md pins Opus review in background, file .opencode/commands/build-feature.md pins Luna build in the current session:
--- description: Review staged changes on Opus agent: reviewer model: opencode/claude-opus-5-5 subagent: true --- Review this diff for bugs, security and missing tests: !`git diff --cached`
--- description: Build one feature step on Luna agent: builder model: opencode/gpt-6-luna subagent: false --- Build $ARGUMENTS in one small step with tests. Show the diff and stop for review.
Run as /review and /build-feature cursor pagination for orders. Command model beats agent model beats session model, so explicit pins always win.
The agent loop
Keep the loop explicit and boring: plan one step, execute exactly one
tool call, record the observation in short-term memory, repeat. Cap the
iterations (twenty is plenty for most tasks) and define the stop
conditions up front: done, blocked, or out of budget. The
steps field enforces the cap — on the final step
tools are removed and a text summary is forced.
Log every iteration. When an agent misbehaves, the trace tells you in
seconds whether the planner, a tool, or the instructions failed. Example
trace prompt that works on all three models:
Find where request timeouts are configured, change the default to 30 seconds, run the relevant tests
— typically grep, read, edit, shell in that order.
Tools make the agent
A model with five sharp tools beats a smarter model with one dull tool.
Design tools like APIs for a junior colleague: one purpose per tool,
strict input validation, and error messages that say what to try next.
In OpenCode the fixed core is
read, glob, grep, edit, write, shell, webfetch,
websearch, question, skill, subagent, execute plus MCP tools named
server_tool.
Gate them per role. Example trio: triage denies
edit and shell, builder
asks for shell except tests, reviewer denies everything except
read, glob, grep, webfetch plus one skill.
Behavior that must hold across sessions belongs in
skills:
tool choice, file layout, output format.
From demo to production
Demos survive on the happy path; production is everything else. Graduate in this order, with a concrete gate per step:
- 1. Sandbox side effects: builder asks for shell, denies push. Run git diff --stat before every commit.
- 2. Human approval: migration and deploy skills show the diff and wait. The question tool asks before breaking APIs.
- 3. Persist memory: commit AGENTS.md, skills and agents so a restart reloads the same guidance.
- 4. Measure per task: track success on triage, build, review separately. Fix the worst role first — often triggers, not the model.
Repeat until the numbers, not impressions, say it is ready. Keep V1 setup until V2 behavior is verified; supported V1 fields keep working, only plugins and server API break intentionally.
Memory that survives restarts
Short-term memory (the running trace) dies with the process; decisions must land in files to survive. Keep three stores: global ~/.config/opencode/AGENTS.md for everywhere rules, root AGENTS.md for repo rules, nested packages/web/AGENTS.md for area rules. Example root file in three lines:
# Project instructions - Run npm test after changing TypeScript. - Keep database queries in src/database. - Do not edit generated files directly.
The agent reads all three on start plus nested files discovered while exploring. Edits to upward files apply before the next request, nested edits after reload need a new session. Moving a session keeps instruction state, reverting clears and reloads it.
Evals before opinions
Ten fixed tasks with checkable outcomes beat a hundred demo impressions. Starter suite for these four agents:
- Triage x3: explain login flow, route a docs fix vs a feature, refuse a secrets task. Must not edit.
- Builder x3: add validation with tests green, rename across two files, keep public API stable.
- Reviewer x2: catch missing 401 on expired token, demand a test for refresh replay. Must not edit.
- Orchestrator x2: plan pagination in three bullets, fan out and merge three child results.
Run the suite on every prompt, tool or model change and keep the history: a two-point drop after an improvement is the norm, not the exception. Try the same suite on Spark Free, Luna and Opus once — the gap tells you which role deserves the expensive model.
Article author: Arthur Isaev
| AI | |
| Creating and developing agents | |
| Writing skills for AI assistants | |
| Models for OpenCode | |
| OpenCode coding agent | |
| One API key for 300+ models |