Skip to content

Agents System

Agents are execution modes with specific permissions, prompts, and configurations.

Agent Definition

typescript
// packages/opencode/src/agent/agent.ts
namespace Agent {
  const Info = z.object({
    name: z.string(),
    description: z.string().optional(),
    mode: z.enum(["subagent", "primary", "all"]),
    native: z.boolean().optional(),
    hidden: z.boolean().optional(),
    topP: z.number().optional(),
    temperature: z.number().optional(),
    color: z.string().optional(),
    permission: PermissionNext.Ruleset,
    model: z
      .object({
        modelID: z.string(),
        providerID: z.string(),
      })
      .optional(),
    variant: z.string().optional(),
    prompt: z.string().optional(),
    options: z.record(z.string(), z.any()),
    steps: z.number().int().positive().optional(),
  });
}

Built-in Agents

AgentModePurpose
buildprimaryDefault - full tool access
planprimaryRead-only planning mode
generalsubagentParallel task execution
exploresubagentFast codebase exploration
compactionprimaryContext compaction (hidden)
titleprimaryGenerate session titles (hidden)
summaryprimaryGenerate summaries (hidden)

Agent Modes

typescript
type Mode = "primary" | "subagent" | "all";

// primary: Main conversation agent
// subagent: Spawned for specific tasks
// all: Can be used as either

Default Permissions

typescript
const defaults = PermissionNext.fromConfig({
  "*": "allow", // Allow all by default
  doom_loop: "ask", // Ask on potential loops
  external_directory: {
    "*": "ask", // Ask for external dirs
    [Truncate.GLOB]: "allow", // Allow truncation temp
  },
  question: "deny", // No questions by default
  plan_enter: "deny",
  plan_exit: "deny",
  read: {
    "*": "allow",
    "*.env": "ask", // Ask before reading .env
    "*.env.*": "ask",
    "*.env.example": "allow",
  },
});

Agent-Specific Permissions

Build Agent

typescript
build: {
  permission: merge(defaults, {
    question: "allow",
    plan_enter: "allow",
  });
}

Plan Agent

typescript
plan: {
  permission: merge(defaults, {
    question: "allow",
    plan_exit: "allow",
    edit: {
      "*": "deny", // No edits except plans
      ".opencode/plans/*.md": "allow",
    },
  });
}

Explore Agent

typescript
explore: {
  permission: merge(defaults, {
    "*": "deny", // Deny all by default
    grep: "allow",
    glob: "allow",
    list: "allow",
    bash: "allow",
    webfetch: "allow",
    websearch: "allow",
    codesearch: "allow",
    read: "allow",
  });
}

Creating Custom Agents

1. Create agent file

.opencode/agent/my-agent.md:

yaml
---
mode: subagent
description: Specialized agent for X tasks
model: anthropic/claude-3-sonnet
color: "#FF5733"
tools:
  read: true
  grep: true
  glob: true
---

You are a specialized agent for X tasks.

## Instructions

1. First, analyze the input
2. Then, process accordingly
3. Finally, return results

2. Agent is auto-discovered

Agents in .opencode/agent/ or .opencode/agents/ are automatically loaded.

Agent Configuration

json
// opencode.json
{
  "agent": {
    "build": {
      "model": "anthropic/claude-3-opus",
      "steps": 50,
      "temperature": 0.7
    },
    "my-custom": {
      "mode": "subagent",
      "description": "Custom agent",
      "prompt": "You are a custom agent...",
      "permission": {
        "bash": "deny"
      }
    }
  }
}

Agent Fields

FieldTypeDescription
modelstringModel ID (provider/model)
variantstringModel variant
temperaturenumberSampling temperature
top_pnumberTop-p sampling
promptstringSystem prompt
modeenumprimary/subagent/all
hiddenbooleanHide from UI
colorstringHex color or theme color
stepsnumberMax agentic iterations
permissionobjectTool permissions
disablebooleanDisable agent

Agent Selection

typescript
// Default agent selection
async function defaultAgent() {
  const cfg = await Config.get();

  // Check for configured default
  if (cfg.default_agent) {
    const agent = agents[cfg.default_agent];
    if (agent.mode === "subagent") throw Error("subagent cannot be default");
    if (agent.hidden) throw Error("hidden agent cannot be default");
    return agent.name;
  }

  // Fall back to first visible primary
  const primaryVisible = Object.values(agents).find(
    (a) => a.mode !== "subagent" && a.hidden !== true,
  );
  return primaryVisible.name;
}

After agent execution, reflect:

  • Was the right agent selected?
  • Should I adjust permissions?
  • Are there edge cases to handle?

Subagent Spawning

typescript
// Task tool spawns subagents
TaskTool.execute({
  subagent_type: "general",
  description: "Analyze codebase",
  prompt: "Find all API endpoints",
});

Agent Generation

OpenCode can generate agents from descriptions:

typescript
const result = await Agent.generate({
  description: "Create an agent for code review",
  model: { providerID: "anthropic", modelID: "claude-3-opus" },
});

// Returns:
// {
//   identifier: "code-reviewer",
//   whenToUse: "Use for reviewing pull requests...",
//   systemPrompt: "You are a code reviewer..."
// }

Permission Merging

Permissions are merged in order:

typescript
// 1. Start with defaults
// 2. Merge agent-specific permissions
// 3. Merge user config permissions
item.permission = PermissionNext.merge(defaults, agentSpecific, userConfig);

Integration with Tachikoma

Tachikoma extends the agent system with:

  • Intent-based agent routing
  • Context module loading per agent
  • Skill-based agent definitions
text
.opencode/skills/
├── code-agent/SKILL.md      # Maps to code-agent
├── research-agent/SKILL.md  # Maps to research-agent
└── analysis-agent/SKILL.md  # Maps to analysis-agent

Released under the MIT License.