Skip to content

Commit 0e3da48

Browse files
feat(agent): support per-agent instructions
1 parent 1e65895 commit 0e3da48

File tree

5 files changed

+84
-1
lines changed

5 files changed

+84
-1
lines changed

packages/opencode/src/agent/agent.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export namespace Agent {
3131
})
3232
.optional(),
3333
prompt: z.string().optional(),
34+
instructions: z.array(z.string()).optional(),
3435
tools: z.record(z.string(), z.boolean()),
3536
options: z.record(z.string(), z.any()),
3637
})
@@ -148,13 +149,15 @@ export namespace Agent {
148149
tools: {},
149150
builtIn: false,
150151
}
151-
const { name, model, prompt, tools, description, temperature, top_p, mode, permission, color, ...extra } = value
152+
const { name, model, prompt, tools, description, temperature, top_p, mode, permission, color, instructions, ...extra } =
153+
value
152154
item.options = {
153155
...item.options,
154156
...extra,
155157
}
156158
if (model) item.model = Provider.parseModel(model)
157159
if (prompt) item.prompt = prompt
160+
if (instructions) item.instructions = instructions
158161
if (tools)
159162
item.tools = {
160163
...item.tools,

packages/opencode/src/config/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ export namespace Config {
364364
.regex(/^#[0-9a-fA-F]{6}$/, "Invalid hex color format")
365365
.optional()
366366
.describe("Hex color code for the agent (e.g., #FF5733)"),
367+
instructions: z
368+
.array(z.string())
369+
.optional()
370+
.describe("Additional instruction files or patterns to include for this agent"),
367371
permission: z
368372
.object({
369373
edit: Permission.optional(),

packages/opencode/src/session/prompt.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,9 @@ export namespace SessionPrompt {
556556
)
557557
system.push(...(await SystemPrompt.environment()))
558558
system.push(...(await SystemPrompt.custom()))
559+
if (input.agent.instructions) {
560+
system.push(...(await SystemPrompt.agentInstructions(input.agent.instructions)))
561+
}
559562
// max 2 system prompt messages for caching purposes
560563
const [first, ...rest] = system
561564
system = [first, rest.join("\n")]

packages/opencode/src/session/system.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,37 @@ export namespace SystemPrompt {
116116
return Promise.all(found).then((result) => result.filter(Boolean))
117117
}
118118

119+
export async function agentInstructions(instructions: string[]) {
120+
const paths = new Set<string>()
121+
122+
for (let instruction of instructions) {
123+
if (instruction.startsWith("~/")) {
124+
instruction = path.join(os.homedir(), instruction.slice(2))
125+
}
126+
let matches: string[] = []
127+
if (path.isAbsolute(instruction)) {
128+
matches = await Array.fromAsync(
129+
new Bun.Glob(path.basename(instruction)).scan({
130+
cwd: path.dirname(instruction),
131+
absolute: true,
132+
onlyFiles: true,
133+
}),
134+
).catch(() => [])
135+
} else {
136+
matches = await Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => [])
137+
}
138+
matches.forEach((path) => paths.add(path))
139+
}
140+
141+
const found = Array.from(paths).map((p) =>
142+
Bun.file(p)
143+
.text()
144+
.catch(() => "")
145+
.then((x) => "Instructions from: " + p + "\n" + x),
146+
)
147+
return Promise.all(found).then((result) => result.filter(Boolean))
148+
}
149+
119150
export function summarize(providerID: string) {
120151
switch (providerID) {
121152
case "anthropic":

packages/web/src/content/docs/agents.mdx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,48 @@ Use the `model` config to override the default model for this agent. Useful for
299299

300300
---
301301

302+
### Instructions
303+
304+
Use `instructions` to load extra instruction files just for a single agent.
305+
306+
```json title="opencode.json"
307+
{
308+
"agent": {
309+
"review": {
310+
"mode": "subagent",
311+
"instructions": ["./code-standards.md", "./.app/docs/*.md", "~/team-guidelines.md"]
312+
}
313+
}
314+
}
315+
```
316+
317+
Instruction files are appended after the agent's prompt and global instructions. Paths can be:
318+
319+
- Relative or glob paths resolved from your project up to the git worktree
320+
- Absolute paths (e.g., "/path/to/file.md")
321+
- Home-relative paths using `~/` (e.g., "~/standards.md")
322+
323+
You can also set `instructions` in markdown agents:
324+
325+
```markdown title="~/.config/opencode/agent/review.md"
326+
---
327+
description: Reviews code for quality and best practices
328+
mode: subagent
329+
instructions:
330+
- ./review-checklist.md
331+
- ./.app/docs/*.md
332+
- ~/coding-standards.md
333+
---
334+
335+
You are in code review mode. Follow the guidelines in the instruction files.
336+
```
337+
338+
:::note
339+
Agent-specific instructions are loaded **in addition to** global `instructions` in your main config. Global instructions apply to all agents; agent instructions apply only to that agent.
340+
:::
341+
342+
---
343+
302344
### Tools
303345

304346
Control which tools are available in this agent with the `tools` config. You can enable or disable specific tools by setting them to `true` or `false`.

0 commit comments

Comments
 (0)