Skip to content

Commit e6f6eaa

Browse files
authored
Merge pull request #76 from telnet2/claude/opencode-agent-modes-da6kW
2 parents 8fd75c5 + bce926b commit e6f6eaa

File tree

1 file changed

+375
-0
lines changed

1 file changed

+375
-0
lines changed
Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
# Agent Modes and Configuration
2+
3+
This document describes the agent mode system in opencode, including how to configure default agents, create custom agents, and disable built-in agents.
4+
5+
---
6+
7+
## Overview
8+
9+
Agents in opencode are specialized AI personas with distinct capabilities, tool access, and permissions. The agent system supports three mode types that determine visibility and usage context.
10+
11+
---
12+
13+
## Agent Modes
14+
15+
Defined in [`src/agent/agent.ts:23`](../src/agent/agent.ts):
16+
17+
```typescript
18+
mode: z.enum(["subagent", "primary", "all"])
19+
```
20+
21+
### Mode Types
22+
23+
| Mode | Description | Tab Cycling | Task Tool |
24+
|------|-------------|-------------|-----------|
25+
| `primary` | Main user-facing agents | Yes | No |
26+
| `subagent` | Called via Task tool only | No | Yes |
27+
| `all` | Functions in both roles | Yes | Yes |
28+
29+
### Visibility Rules
30+
31+
Agents appear in tab cycling if ([`src/agent/agent.ts:269`](../src/agent/agent.ts)):
32+
33+
```typescript
34+
const hasPrimaryAgents = Object.values(result).filter(
35+
(a) => a.mode !== "subagent" && !a.hidden
36+
).length > 0
37+
```
38+
39+
---
40+
41+
## Built-in Agents
42+
43+
Defined in [`src/agent/agent.ts:117-198`](../src/agent/agent.ts):
44+
45+
| Agent | Mode | Hidden | Description |
46+
|-------|------|--------|-------------|
47+
| `build` | primary | No | Default agent with full tool access |
48+
| `plan` | primary | No | Read-only planning agent |
49+
| `general` | subagent | Yes | General-purpose Task tool agent |
50+
| `explore` | subagent | No | Fast codebase exploration |
51+
| `compaction` | primary | Yes | Context compression (internal) |
52+
| `title` | primary | Yes | Title generation (internal) |
53+
| `summary` | primary | Yes | Summary generation (internal) |
54+
55+
### Build Agent
56+
57+
Full tool access with default permissions ([`src/agent/agent.ts:118-125`](../src/agent/agent.ts)):
58+
59+
```typescript
60+
build: {
61+
name: "build",
62+
tools: { ...defaultTools },
63+
options: {},
64+
permission: agentPermission,
65+
mode: "primary",
66+
native: true,
67+
}
68+
```
69+
70+
### Plan Agent
71+
72+
Read-only mode with restricted bash commands ([`src/agent/agent.ts:126-135`](../src/agent/agent.ts)):
73+
74+
```typescript
75+
plan: {
76+
name: "plan",
77+
options: {},
78+
permission: planPermission, // Restricted permissions
79+
tools: { ...defaultTools },
80+
mode: "primary",
81+
native: true,
82+
}
83+
```
84+
85+
Plan mode permissions deny edits and only allow read-only bash commands ([`src/agent/agent.ts:71-115`](../src/agent/agent.ts)):
86+
87+
```typescript
88+
const planPermission = mergeAgentPermissions({
89+
edit: "deny",
90+
bash: {
91+
"git diff*": "allow",
92+
"git log*": "allow",
93+
"grep*": "allow",
94+
"ls*": "allow",
95+
// ... other read-only commands
96+
"*": "ask", // Ask for anything else
97+
},
98+
webfetch: "allow",
99+
}, cfg.permission ?? {})
100+
```
101+
102+
---
103+
104+
## Default Agent
105+
106+
### Configuration
107+
108+
Set the default agent in `opencode.json` ([`src/agent/agent.ts:258-267`](../src/agent/agent.ts)):
109+
110+
```json
111+
{
112+
"default_agent": "build"
113+
}
114+
```
115+
116+
### Resolution Logic
117+
118+
```typescript
119+
const defaultName = cfg.default_agent ?? "build"
120+
const defaultCandidate = result[defaultName]
121+
if (defaultCandidate && defaultCandidate.mode !== "subagent") {
122+
defaultCandidate.default = true
123+
} else {
124+
// Fall back to "build" if configured default is invalid
125+
if (result["build"]) {
126+
result["build"].default = true
127+
}
128+
}
129+
```
130+
131+
### Retrieval
132+
133+
Get the default agent name ([`src/agent/agent.ts:288-292`](../src/agent/agent.ts)):
134+
135+
```typescript
136+
export async function defaultAgent(): Promise<string> {
137+
const agents = await state()
138+
const defaultCandidate = Object.values(agents).find((a) => a.default)
139+
return defaultCandidate?.name ?? "build"
140+
}
141+
```
142+
143+
---
144+
145+
## Disabling Built-in Agents
146+
147+
### Configuration
148+
149+
Disable agents via `opencode.json` using the `disable` property ([`src/config/config.ts:399`](../src/config/config.ts)):
150+
151+
```json
152+
{
153+
"agent": {
154+
"build": {
155+
"disable": true
156+
}
157+
}
158+
}
159+
```
160+
161+
### Implementation
162+
163+
Disabled agents are removed from the agent registry ([`src/agent/agent.ts:199-203`](../src/agent/agent.ts)):
164+
165+
```typescript
166+
for (const [key, value] of Object.entries(cfg.agent ?? {})) {
167+
if (value.disable) {
168+
delete result[key]
169+
continue
170+
}
171+
// ... rest of agent configuration
172+
}
173+
```
174+
175+
### Validation
176+
177+
At least one primary agent must exist ([`src/agent/agent.ts:269-275`](../src/agent/agent.ts)):
178+
179+
```typescript
180+
const hasPrimaryAgents = Object.values(result).filter(
181+
(a) => a.mode !== "subagent" && !a.hidden
182+
).length > 0
183+
184+
if (!hasPrimaryAgents) {
185+
throw new Config.InvalidError({
186+
path: "config",
187+
message: "No primary agents are available. Please configure at least one agent with mode 'primary' or 'all'.",
188+
})
189+
}
190+
```
191+
192+
---
193+
194+
## Creating Custom Agents
195+
196+
### Via Configuration File
197+
198+
Create `.opencode/agent/myagent.md`:
199+
200+
```markdown
201+
---
202+
description: "When to use this agent"
203+
mode: "primary"
204+
tools:
205+
edit: true
206+
bash: true
207+
---
208+
Your custom system prompt here...
209+
```
210+
211+
### Via Config JSON
212+
213+
In `opencode.json`:
214+
215+
```json
216+
{
217+
"agent": {
218+
"myagent": {
219+
"description": "My custom coding assistant",
220+
"mode": "primary",
221+
"prompt": "You are a helpful assistant...",
222+
"tools": {
223+
"edit": true,
224+
"bash": true
225+
}
226+
}
227+
}
228+
}
229+
```
230+
231+
### Via CLI
232+
233+
```bash
234+
opencode agent create \
235+
--path .opencode/agent \
236+
--description "My custom agent" \
237+
--mode primary
238+
```
239+
240+
### Default Mode for Custom Agents
241+
242+
Custom agents default to `mode: "all"` if not specified ([`src/agent/agent.ts:205-213`](../src/agent/agent.ts)):
243+
244+
```typescript
245+
if (!item)
246+
item = result[key] = {
247+
name: key,
248+
mode: "all", // Default mode
249+
permission: agentPermission,
250+
options: {},
251+
tools: {},
252+
native: false,
253+
}
254+
```
255+
256+
---
257+
258+
## Agent Switching
259+
260+
### Plan to Build Transition
261+
262+
When switching from Plan to Build, a reminder is injected ([`src/session/prompt.ts:1018-1028`](../src/session/prompt.ts)):
263+
264+
```typescript
265+
const wasPlan = input.messages.some(
266+
(msg) => msg.info.role === "assistant" && msg.info.agent === "plan"
267+
)
268+
if (wasPlan && input.agent.name === "build") {
269+
userMessage.parts.push({
270+
// ... injects build-switch.txt content
271+
text: BUILD_SWITCH,
272+
synthetic: true,
273+
})
274+
}
275+
```
276+
277+
The switch prompt ([`src/session/prompt/build-switch.txt`](../src/session/prompt/build-switch.txt)):
278+
279+
```
280+
Your operational mode has changed from plan to build.
281+
You are no longer in read-only mode.
282+
You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.
283+
```
284+
285+
### Plan Mode Reminder
286+
287+
Plan mode injects a read-only constraint ([`src/session/prompt.ts:1007-1017`](../src/session/prompt.ts)):
288+
289+
```typescript
290+
if (input.agent.name === "plan") {
291+
userMessage.parts.push({
292+
// ... injects plan.txt content
293+
text: PROMPT_PLAN,
294+
synthetic: true,
295+
})
296+
}
297+
```
298+
299+
---
300+
301+
## Agent Configuration Schema
302+
303+
Full schema from [`src/config/config.ts:393-410`](../src/config/config.ts):
304+
305+
```typescript
306+
z.object({
307+
model: z.string().optional(), // "provider/model" format
308+
temperature: z.number().optional(),
309+
top_p: z.number().optional(),
310+
prompt: z.string().optional(), // System prompt
311+
tools: z.record(z.string(), z.boolean()).optional(),
312+
disable: z.boolean().optional(), // Remove agent entirely
313+
description: z.string().optional(), // When to use
314+
mode: z.enum(["subagent", "primary", "all"]).optional(),
315+
color: z.string().optional(), // Hex color for UI
316+
maxSteps: z.number().int().positive().optional(),
317+
permission: z.object({
318+
edit: Permission,
319+
bash: z.record(z.string(), Permission),
320+
skill: z.record(z.string(), Permission),
321+
webfetch: Permission.optional(),
322+
doom_loop: Permission.optional(),
323+
external_directory: Permission.optional(),
324+
}).optional(),
325+
})
326+
```
327+
328+
---
329+
330+
## Example: Replace Build with Custom Agent
331+
332+
```json
333+
{
334+
"default_agent": "coder",
335+
"agent": {
336+
"build": {
337+
"disable": true
338+
},
339+
"plan": {
340+
"disable": true
341+
},
342+
"coder": {
343+
"description": "Expert coding assistant",
344+
"mode": "primary",
345+
"prompt": "You are an expert software engineer...",
346+
"tools": {
347+
"edit": true,
348+
"bash": true,
349+
"read": true,
350+
"glob": true,
351+
"grep": true
352+
}
353+
}
354+
}
355+
}
356+
```
357+
358+
This configuration:
359+
1. Disables built-in `build` and `plan` agents
360+
2. Creates a custom `coder` agent as primary
361+
3. Sets `coder` as the default agent
362+
4. Tab cycling will only show `coder` and other custom primary agents
363+
364+
---
365+
366+
## Related Files
367+
368+
| File | Purpose |
369+
|------|---------|
370+
| [`src/agent/agent.ts`](../src/agent/agent.ts) | Agent definitions and registry |
371+
| [`src/config/config.ts`](../src/config/config.ts) | Configuration schema |
372+
| [`src/session/prompt.ts`](../src/session/prompt.ts) | Prompt assembly and mode switching |
373+
| [`src/session/prompt/plan.txt`](../src/session/prompt/plan.txt) | Plan mode constraint |
374+
| [`src/session/prompt/build-switch.txt`](../src/session/prompt/build-switch.txt) | Plan-to-build transition |
375+
| [`src/cli/cmd/tui/context/local.tsx`](../src/cli/cmd/tui/context/local.tsx) | TUI agent cycling |

0 commit comments

Comments
 (0)