Skip to content

How to Create Custom Agents in OpenCode CLI: A Complete Guide

Purpose

This post shows how to create custom agents and subagents in OpenCode CLI to specialize AI assistants for specific tasks like code review, security audits, or documentation.

The Problem

When I first started using OpenCode CLI, I used the default agent for everything. Code reviews, security audits, documentation - all handled by one generic assistant.

Here’s what happened:

User: "Review my code for security issues"
OpenCode: "I've reviewed your code. Here are some suggestions:
1. Add input validation
2. Use parameterized queries
3. Consider rate limiting"

The feedback was generic. It didn’t catch domain-specific issues. I missed SQL injection vulnerabilities because the default agent wasn’t specialized for security.

I wanted different agents for different tasks:

  • A code-reviewer agent that focuses on code quality and patterns
  • A security-reviewer agent that checks for vulnerabilities
  • A planner agent that breaks down complex features
  • A tdd-guide agent that enforces test-driven development

The Solution

OpenCode CLI supports custom agents through two approaches:

  1. JSON Configuration in opencode.json
  2. Markdown Files in agent directories

Agents come in two modes:

  • Primary agents: Main agents you interact with directly
  • Subagents: Specialized agents invoked by primary agents for specific tasks

Understanding Agent Modes

Before creating agents, I needed to understand the difference:

Primary Agent (You interact with this)
├── Delegates to ──▶ Subagent 1 (code-reviewer)
├── Delegates to ──▶ Subagent 2 (security-reviewer)
└── Delegates to ──▶ Subagent 3 (planner)

Primary agents handle conversations. Subagents handle specialized tasks. This separation keeps each agent focused.

JSON Configuration Approach

The first way to create agents is through the opencode.json configuration file.

Location

OpenCode looks for configuration in two places:

  • Global: ~/.config/opencode/opencode.json (applies to all projects)
  • Project: ./opencode.json (overrides global settings)

Basic Agent Configuration

I created a code-reviewer agent in my project’s opencode.json:

opencode.json
{
"agents": [
{
"name": "code-reviewer",
"mode": "subagent",
"description": "Reviews code for quality, patterns, and best practices",
"model": "claude-sonnet-4-20250514",
"systemPrompt": "You are a code reviewer. Focus on: code quality, design patterns, error handling, and maintainability. Be thorough but concise."
}
]
}

Each field matters:

  • name: The identifier used to invoke the agent
  • mode: Either primary or subagent
  • description: What the agent does (shown in UI)
  • model: Which Claude model to use
  • systemPrompt: Instructions that define agent behavior

Adding Permissions

For agents that need specific capabilities, I add permissions:

opencode.json
{
"agents": [
{
"name": "security-reviewer",
"mode": "subagent",
"description": "Scans code for security vulnerabilities",
"model": "claude-sonnet-4-20250514",
"permissions": {
"read": true,
"write": false,
"execute": false,
"network": false
},
"systemPrompt": "You are a security expert. Identify vulnerabilities including: SQL injection, XSS, CSRF, hardcoded secrets, insecure deserialization. Provide severity ratings and remediation steps."
}
]
}

Permissions restrict what an agent can do:

  • read: Can read files
  • write: Can modify files
  • execute: Can run shell commands
  • network: Can make network requests

A security reviewer only needs read access because it analyzes code without making changes.

Creating Primary Agents

For a custom primary agent, I set mode to primary:

opencode.json
{
"agents": [
{
"name": "yolo",
"mode": "primary",
"description": "Fast agent that bypasses all permission checks",
"model": "claude-sonnet-4-20250514",
"permissions": {
"dangerouslySkipPermissions": true
},
"systemPrompt": "You are a fast development agent. Skip confirmations, make changes directly. Focus on speed over caution."
}
]
}

This is useful for trusted environments where I want fast iteration without permission prompts.

Markdown Agent Configuration

The second approach uses Markdown files in agent directories.

Directory Structure

OpenCode looks for agent definitions in:

  • Global: ~/.config/opencode/agents/
  • Project: .opencode/agents/

I created a directory structure:

.opencode/
└── agents/
├── code-reviewer.md
├── security-reviewer.md
└── planner.md

Markdown Agent Format

Each Markdown file defines one agent:

.opencode/agents/planner.md
---
name: planner
mode: subagent
description: Creates detailed implementation plans for complex features
model: claude-sonnet-4-20250514
permissions:
read: true
write: false
execute: false
---
You are a planning expert. When given a feature request:
1. Break down the feature into small, implementable tasks
2. Identify dependencies between tasks
3. Estimate complexity for each task
4. Flag potential risks and blockers
5. Suggest the order of implementation
Always start with high-level architecture before diving into implementation details.

The YAML frontmatter contains the configuration. The body contains the system prompt.

Why Markdown?

Markdown files have advantages over JSON:

  1. Longer system prompts: System prompts can span multiple paragraphs
  2. Version control friendly: Easy to diff and review changes
  3. Documentation inline: Add comments and examples within the prompt
  4. Team sharing: Commit .opencode/agents/ to share with team

Interactive Creation with opencode agent create

OpenCode provides an interactive command to create agents:

Terminal window
opencode agent create

This launches an interactive prompt:

? Agent name: security-reviewer
? Agent mode: (primary/subagent): subagent
? Description: Scans code for security vulnerabilities
? Model: claude-sonnet-4-20250514
? Allow read?: Yes
? Allow write?: No
? Allow execute?: No
? Allow network?: No
? System prompt: (opens editor)

After completing the prompts, OpenCode creates the agent configuration.

Where It Saves

The command saves to different locations based on scope:

Terminal window
# Global agent (available in all projects)
opencode agent create --global
# Project agent (available in current project only)
opencode agent create

Global agents go to ~/.config/opencode/agents/. Project agents go to .opencode/agents/.

Invoking Subagents

After creating subagents, I invoke them from primary agents or directly.

From Primary Agent

In my primary agent’s system prompt, I reference subagents:

~/.config/opencode/agents/orchestrator.md
---
name: orchestrator
mode: primary
description: Manages workflows of multiple subagents
model: claude-sonnet-4-20250514
---
You are an orchestrator agent. Delegate tasks to specialized subagents:
- Use **code-reviewer** when user asks for code review
- Use **security-reviewer** when user asks for security audit
- Use **planner** when user starts a new feature
- Use **tdd-guide** when user writes tests
Invoke subagents by name. For example: "Use the code-reviewer agent to analyze the recent changes."

Direct Invocation

I can also invoke agents directly via CLI:

Terminal window
# Invoke a specific agent
opencode --agent security-reviewer
# Or in conversation
"Use security-reviewer to check app.py"

Agent Workflow Example

Here’s a typical workflow:

Me: "I'm starting a new authentication feature"
Orchestrator: "I'll use the planner agent to create an implementation plan."
[Invokes planner subagent]
Planner: "Here's the implementation plan:
1. Design database schema for users
2. Create password hashing utility
3. Implement login endpoint
4. Add session management
5. Write authentication middleware
6. Create tests for each component"
Me: "Great, let's start implementing"
Orchestrator: "I'll use tdd-guide to ensure we follow TDD practices."
[Invokes tdd-guide subagent]
TDD-Guide: "Following TDD workflow for authentication:
1. RED: Write test for password hashing
2. GREEN: Implement password hashing
3. REFACTOR: Optimize hashing algorithm"

Common Mistakes

I made several mistakes when I started creating custom agents. Here’s what I learned:

Mistake 1: Too Many Primary Agents

At first, I created multiple primary agents:

opencode.json
{
"agents": [
{"name": "frontend", "mode": "primary", ...},
{"name": "backend", "mode": "primary", ...},
{"name": "database", "mode": "primary", ...},
{"name": "testing", "mode": "primary", ...}
]
}

This caused confusion. I didn’t know which agent to use. The better approach:

opencode.json
{
"agents": [
{
"name": "orchestrator",
"mode": "primary",
"description": "Main agent that delegates to subagents",
...
},
{"name": "frontend", "mode": "subagent", ...},
{"name": "backend", "mode": "subagent", ...},
{"name": "database", "mode": "subagent", ...},
{"name": "testing", "mode": "subagent", ...}
]
}

One primary agent, many subagents. This keeps interactions simple.

Mistake 2: Overly Broad System Prompts

My first system prompt was too vague:

You are a helpful assistant that reviews code.

The agent didn’t know what to focus on. Better to be specific:

You are a code reviewer. Focus on:
- Code quality: readability, naming conventions, function length
- Design patterns: proper use of patterns, SOLID principles
- Error handling: try-catch blocks, error messages, edge cases
- Maintainability: code duplication, coupling, testability
Provide actionable feedback with specific line references.
Rate severity: CRITICAL, HIGH, MEDIUM, LOW.

Mistake 3: Wrong Permission Levels

I initially gave all agents full permissions:

opencode.json
{
"permissions": {
"read": true,
"write": true,
"execute": true,
"network": true
}
}

This is dangerous. A code reviewer shouldn’t execute commands. A planner shouldn’t write files. I learned to follow the principle of least privilege:

opencode.json
{
"name": "code-reviewer",
"permissions": {
"read": true,
"write": false,
"execute": false,
"network": false
}
}

Mistake 4: Ignoring Model Selection

I used the same model for all agents. But different tasks need different models:

opencode.json
{
"agents": [
{
"name": "planner",
"model": "claude-opus-4-20250514",
"reason": "Planning requires deep reasoning"
},
{
"name": "code-reviewer",
"model": "claude-sonnet-4-20250514",
"reason": "Code review needs fast, accurate feedback"
},
{
"name": "formatter",
"model": "claude-haiku-4-20250514",
"reason": "Formatting is simple and frequent"
}
]
}

Opus for complex reasoning, Sonnet for balanced tasks, Haiku for simple operations.

Mistake 5: Not Testing Agents

I created agents but never tested them. When I needed them, they didn’t work as expected. Now I test immediately:

Terminal window
# Create agent
opencode agent create
# Test agent
opencode --agent my-new-agent
> "Test prompt to verify agent behavior"

Real Examples

Here are the agents I use daily:

Code Reviewer Agent

.opencode/agents/code-reviewer.md
---
name: code-reviewer
mode: subagent
description: Reviews code for quality and best practices
model: claude-sonnet-4-20250514
permissions:
read: true
write: false
execute: false
network: false
---
Review code with focus on:
**Code Quality**
- Function length (under 50 lines ideal)
- File size (under 800 lines)
- Naming clarity
- Comment necessity
**Design Patterns**
- Proper abstraction levels
- SOLID principles adherence
- Pattern misuse detection
**Error Handling**
- Try-catch completeness
- Error message clarity
- Edge case coverage
**Output Format**

Summary

Brief overall assessment

Critical Issues

  • [CRITICAL] Description with file:line

High Priority

  • [HIGH] Description with file:line

Suggestions

  • [LOW] Optional improvements

Security Reviewer Agent

.opencode/agents/security-reviewer.md
---
name: security-reviewer
mode: subagent
description: Scans code for security vulnerabilities
model: claude-sonnet-4-20250514
permissions:
read: true
write: false
execute: false
network: false
---
Scan for security vulnerabilities:
**Injection Attacks**
- SQL injection in queries
- Command injection in shell calls
- XSS in rendered content
**Authentication & Authorization**
- Hardcoded credentials
- Weak password hashing
- Missing access controls
**Data Protection**
- Sensitive data in logs
- Unencrypted storage
- Insecure transmission
**Output Format**

Security Audit Report

CRITICAL

  • [CRITICAL] Vulnerability type - Location - Remediation

HIGH

  • [HIGH] Vulnerability type - Location - Remediation

MEDIUM

  • [MEDIUM] Vulnerability type - Location - Remediation

TDD Guide Agent

.opencode/agents/tdd-guide.md
---
name: tdd-guide
mode: subagent
description: Enforces test-driven development workflow
model: claude-sonnet-4-20250514
permissions:
read: true
write: true
execute: true
network: false
---
Guide developers through TDD workflow:
**RED Phase**
1. Write test first
2. Run test - it MUST FAIL
3. Confirm test is valid
**GREEN Phase**
1. Write minimal implementation
2. Run test - it MUST PASS
3. Verify test passes
**REFACTOR Phase**
1. Improve code structure
2. Run tests - must still pass
3. Check coverage (aim for 80%+)
**Rules**
- NEVER write implementation before test
- NEVER skip running tests
- NEVER commit failing tests
**Output**
After each phase, report:
- What was done
- Test results
- Coverage percentage

Summary

In this post, I showed how to create custom agents in OpenCode CLI. The key points are:

  • Use JSON configuration for simple agents in opencode.json
  • Use Markdown files for complex agents with long system prompts
  • Primary agents handle conversations, subagents handle tasks
  • Set appropriate permissions for each agent’s role
  • Test agents immediately after creation
  • Choose models based on task complexity

Next steps:

  1. Start with one subagent for a task you do frequently
  2. Test the agent with real code
  3. Iterate on the system prompt based on results
  4. Add more subagents as you identify specialized needs
  5. Create a primary agent to orchestrate your subagents

Custom agents transform OpenCode from a generic assistant into a team of specialized experts. Each agent focuses on what it does best, improving code quality and development efficiency.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments