opencode System Prompt 构建机制 & AGENTS.md注入机制
概述
opencode 的 System Prompt 由多个部分动态拼接而成,在每次 LLM 调用前组装。整体结构如下:
css
[Provider/Agent 基础提示词]
+ [环境信息 env]
+ [指令文件内容 instructions]
+ [技能列表 skills]
核心组装逻辑分布在两个文件:
packages/opencode/src/session/llm.ts--- 最终拼接packages/opencode/src/session/prompt.ts--- 准备 env / instructions / skills
各部分详解
1. Provider/Agent 基础提示词
来源: packages/opencode/src/session/system.ts 的 provider() 函数
组装位置: packages/opencode/src/session/llm.ts:103
css
...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model))
逻辑:
- 如果当前 Agent 在配置中定义了自定义
prompt,直接使用该 prompt - 否则根据模型 ID 自动选择内置 provider 提示词文件:
| 模型匹配规则 | 提示词文件 |
|---|---|
包含 claude |
prompt/anthropic.txt |
包含 gpt-4、o1、o3 |
prompt/beast.txt |
包含 codex |
prompt/codex.txt |
包含其他 gpt |
prompt/gpt.txt |
包含 gemini- |
prompt/gemini.txt |
包含 trinity |
prompt/trinity.txt |
包含 kimi |
prompt/kimi.txt |
| 其他 | prompt/default.txt |
所有提示词文件位于 packages/opencode/src/session/prompt/ 目录。
内置示例:prompt/anthropic.txt(Claude 模型使用)
vbnet
You are OpenCode, the best coding agent on the planet.
You are an interactive CLI tool that helps users with software engineering tasks.
Use the instructions below and the tools available to you to assist the user.
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are
confident that the URLs are for helping the user with programming.
If the user asks for help or wants to give feedback inform them of the following:
- ctrl+p to list available actions
- To give feedback, users should report the issue at
https://github.com/anomalyco/opencode
# Tone and style
- Only use emojis if the user explicitly requests it.
- Your output will be displayed on a command line interface.
...
# Professional objectivity
Prioritize technical accuracy and truthfulness over validating the user's beliefs.
...
# Task Management
You have access to the TodoWrite tools to help you manage and plan tasks.
Use these tools VERY frequently to ensure that you are tracking your tasks.
...
# Doing tasks
The user will primarily request you perform software engineering tasks.
...
# Tool usage policy
- When doing file search, prefer to use the Task tool in order to reduce context usage.
...
# Code References
When referencing specific functions or pieces of code include the pattern
`file_path:line_number` to allow the user to easily navigate to the source code location.
完整内容见
packages/opencode/src/session/prompt/anthropic.txt。
default.txt用于其他模型,风格更简洁,强调"回答少于 4 行、不加无用前缀"。
Agent 自定义 prompt 示例 (opencode.json):
json
{
"agent": {
"my-agent": {
"prompt": "你是一个专注于代码审查的助手,只读取文件,不修改。"
}
}
}
2. 环境信息(env)
来源: packages/opencode/src/session/system.ts 的 environment() 方法
组装位置: packages/opencode/src/session/prompt.ts:1444
bash
Effect.sync(() => sys.environment(model))
每次调用时动态生成,内容如下:
vbnet
You are powered by the model named <model.api.id>. The exact model ID is <providerID>/<modelID>
Here is some useful information about the environment you are running in:
<env>
Working directory: /path/to/project
Workspace root folder: /path/to/worktree
Is directory a git repo: yes
Platform: darwin
Today's date: Mon May 04 2026
</env>
3. 指令文件(instructions)
来源: packages/opencode/src/session/instruction.ts 的 system() 方法
组装位置: packages/opencode/src/session/prompt.ts:1445
scss
instruction.system().pipe(Effect.orDie)
system() 的完整逻辑:
- 调用
systemPaths()收集所有本地文件路径(Set<string>) - 提取
config.instructions中的远程 URL - 并发读取本地文件(最多 8 个并发)
- 并发拉取远程 URL(最多 4 个并发,超时 5 秒)
- 空文件 / 拉取失败的条目自动跳过
最终每条内容格式:
javascript
Instructions from: /absolute/path/to/AGENTS.md
<文件内容>
AGENTS.md 加载机制
查找规则(systemPaths())
按以下三步收集文件路径,结果存入 Set<string>(自动去重,顺序:全局 → 项目 → 额外)。
第一步:全局文件(最多加载 1 个)
globalFiles() 返回候选列表,按顺序取第一个存在的文件后 break:
javascript
1. $OPENCODE_CONFIG_DIR/AGENTS.md (仅当 OPENCODE_CONFIG_DIR 已设置)
2. ~/.config/opencode/AGENTS.md
3. ~/.claude/CLAUDE.md (除非设置了 OPENCODE_DISABLE_CLAUDE_CODE_PROMPT)
效果: 全局只注入一个文件,不会叠加多个。
第二步:项目文件(findUp 向上查找,同类型全部加载)
使用 findUp(file, ctx.directory, ctx.worktree) 实现:
从 working directory 开始,依次向上收集各层目录中存在该文件名的路径,
直到 worktree 根目录为止(含根目录)。
文件类型优先级(FILES 数组):
ini
const FILES = ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"]
查找逻辑:
- 对
AGENTS.md执行findUp→ 若找到任意匹配,把所有匹配都加入,然后 break(不再查 CLAUDE.md、CONTEXT.md) - 若
AGENTS.md一个都没有,对CLAUDE.md执行同样逻辑 - 若前两者都没有,对
CONTEXT.md(已废弃)执行
关键点:同类型文件在路径上的多个实例都会被加载。
示例目录结构:
bash
/project/ ← worktree 根
├── AGENTS.md ← ✅ 被加载(findUp 命中)
├── src/
│ ├── AGENTS.md ← ✅ 被加载(findUp 命中,与根目录同类型)
│ └── auth/ ← working directory(opencode 在此启动)
└── opencode.json
若 working directory 是 /project/src/auth/,findUp("AGENTS.md", "/project/src/auth/", "/project/") 会依次检查:
/project/src/auth/AGENTS.md--- 不存在,跳过/project/src/AGENTS.md--- 存在,收集/project/AGENTS.md--- 存在,收集
结果:/project/src/AGENTS.md 和 /project/AGENTS.md 都被注入。
⚠️ 从根目录启动时,子目录的 AGENTS.md 不会被加载
findUp 只向上查找,不向下扫描子目录。
ini
/project/ ← working directory = worktree 根,在此启动 opencode
├── AGENTS.md ← ✅ 被加载
├── src/
│ └── AGENTS.md ← ❌ 不会被加载(子目录,findUp 不向下扫描)
└── packages/
└── AGENTS.md ← ❌ 不会被加载(同上)
findUp("AGENTS.md", "/project/", "/project/") 的执行过程:
- start 与 stop 相同,只检查
/project/AGENTS.md,立即结束 - 子目录的 AGENTS.md 完全不在查找范围内
如果需要加载子目录的 AGENTS.md,有两种方式:
-
config.instructionsglob 通配符(静态,启动时加载):json{ "instructions": ["**/AGENTS.md"] }利用
globUp在每层目录执行 glob,可匹配子目录。注意:
globUp是从当前目录向上扫描,不是递归向下,此方式需结合相对路径 glob 才能覆盖子目录。更直接的方式是使用绝对路径:
"/project/**/AGENTS.md" -
动态加载 (按需,读取文件时触发):
当
read工具读取子目录中的文件时,resolve()方法会自动将该文件附近的 AGENTS.md 注入为 tool result,详见下方"动态加载"章节。
第三步:配置额外指令(config.instructions)
来自 opencode.json 中的 instructions 数组,支持四种格式:
perl
{
"instructions": [
"docs/style-guide.md", // 相对路径 → globUp(从 working dir 向上每层 glob)
"~/notes/coding-rules.md", // ~ 路径 → 展开为绝对路径后 glob
"/shared/team-rules/*.md", // 绝对路径 → 直接 glob(支持通配符)
"https://example.com/rules.md" // URL → HTTP GET(超时 5 秒)
]
}
相对路径 / ~/ 路径的查找行为(globUp):
scss
从 working directory 开始,在每一层目录执行 glob(pattern),
收集所有匹配文件,然后向上到 worktree 根。
与 findUp 的区别:
findUp:精确文件名,找到即 break(按类型)globUp:支持通配符,不 break,沿路径每层都 glob,结果全部收集
示例:instructions: ["docs/*.md"] 会扫描从当前目录到 worktree 根路径上,每层 docs/ 子目录中的所有 .md 文件。
URL 的获取行为:
- 仅支持
http://和https:// - 发起 GET 请求,超时 5 秒,失败或超时则跳过(不报错)
- 响应体以 UTF-8 解码后整体注入
完整 instructions 注入示例
假设项目结构:
arduino
/project/
├── AGENTS.md # "禁止直接提交 main 分支"
├── src/
│ └── AGENTS.md # "src 目录使用 TypeScript strict 模式"
└── opencode.json # instructions: ["docs/style.md", "https://rules.example.com/base.md"]
~/.config/opencode/AGENTS.md 存在,内容为 "遵循公司编码规范"。
注入到 System Prompt 的 instructions 部分(4 条):
javascript
Instructions from: /Users/mac/.config/opencode/AGENTS.md
遵循公司编码规范
Instructions from: /project/src/AGENTS.md
src 目录使用 TypeScript strict 模式
Instructions from: /project/AGENTS.md
禁止直接提交 main 分支
Instructions from: /project/docs/style.md
<style.md 文件内容>
Instructions from: https://rules.example.com/base.md
<远程规则内容>
动态加载(对话中)
除了启动时的静态加载,在对话过程中读取文件时,opencode 还会动态注入附近的指令文件。
触发时机: 使用 read 工具读取某个文件后(state.status === "completed")
机制 (instruction.ts 的 resolve() 方法):
-
取被读取文件所在目录,向上逐级走到 worktree 根
-
每层检查
AGENTS.md→CLAUDE.md→CONTEXT.md(取第一个存在的) -
跳过以下情况:
- 已在启动时 System Prompt 中加载的(
sys.has(found)) - 当前 assistant 消息中已经注入过的(
claimsMap 追踪,每条消息重置) - 正在被读取的文件本身(
found === target) - 已在本对话中由其他 read 工具加载过的(
extract(messages)扫描历史)
- 已在启动时 System Prompt 中加载的(
-
内容以附加
tool result的形式注入,不进入 System Prompt
效果示例:
bash
read("src/auth/login.ts")
→ 检查 src/auth/AGENTS.md → 存在 → 注入
→ 检查 src/AGENTS.md → 已在系统启动时加载 → 跳过
→ 检查 /project/AGENTS.md → 已在系统启动时加载 → 跳过
4. 技能列表(skills)
来源: packages/opencode/src/session/system.ts 的 skills() 方法
组装位置: packages/opencode/src/session/prompt.ts:1443
scss
sys.skills(agent)
逻辑:
- 若 agent 的权限中禁用了
skill工具,则返回undefined(不注入) - 否则获取当前 agent 可用的 skill 列表,以详细(verbose)格式注入
注入内容格式(system.ts:65-77):
xml
Skills provide specialized instructions and workflows for specific tasks.
Use the skill tool to load a skill when a task matches its description.
<available_skills>
<skill>
<name>commit</name>
<description>Use when the user asks to commit changes</description>
<location>file:///Users/mac/.config/opencode/skills/commit.md</location>
</skill>
<skill>
<name>review</name>
<description>Use for code review tasks</description>
<location>file:///project/.opencode/skills/review.md</location>
</skill>
</available_skills>
生成逻辑 (packages/opencode/src/skill/index.ts:264):
Skill.fmt(list, { verbose: true }) 输出 XML 格式,按 skill 名称字母升序排列,每条包含:
| 字段 | 说明 |
|---|---|
<name> |
skill 文件名(不含 .md) |
<description> |
skill frontmatter 中的 description 字段 |
<location> |
skill 文件的 file:// URL 绝对路径 |
若没有任何可用 skill,输出:No skills are currently available.
与 skill 工具描述中的非 verbose 格式对比:
markdown
## Available Skills
- **commit**: Use when the user asks to commit changes
- **review**: Use for code review tasks
System Prompt 使用详细版(verbose),工具描述使用简洁版(non-verbose),两者配合:模型在 System Prompt 中获取完整信息,在工具描述中快速检索。
最终组装
packages/opencode/src/session/llm.ts 中的最终拼接:
less
// 第一个 system block(基础提示词 + env + instructions + skills)
system.push(
[
...(agent.prompt ? [agent.prompt] : SystemPrompt.provider(model)), // 基础提示词
...input.system, // = [...env, ...instructions, ...(skills ? [skills] : [])]
...(user.system ? [user.system] : []), // 用户消息携带的 system(少见)
]
.filter(x => x)
.join("\n")
)
随后触发插件钩子,允许插件修改 system 数组:
perl
plugin.trigger("experimental.chat.system.transform", { sessionID, model }, { system })
若输出格式为 json_schema,还会追加:
lua
IMPORTANT: The user has requested structured output. You MUST use the StructuredOutput tool...
特殊注入(非 System 位置)
以下内容不在 System Prompt 中,而是以合成用户消息部分(synthetic user message part)注入:
| 触发条件 | 内容来源 | 说明 |
|---|---|---|
当前 agent 是 plan |
prompt/plan.txt |
只读模式提醒,禁止文件修改 |
从 plan 切换到 build |
prompt/build-switch.txt |
解除只读限制提醒 |
| 步骤数达到上限 | prompt/max-steps.txt |
作为最后一条 assistant 消息追加,禁用工具 |
完整结构图
css
LLM 调用时的 system 数组
├── [0] 第一块(拼接为单字符串)
│ ├── 基础提示词(provider-specific 或 agent 自定义)
│ ├── env(模型名、工作目录、平台、日期)
│ ├── instructions(AGENTS.md 等文件内容)
│ └── skills(可用 skill 列表,详细版)
└── [1+] 插件通过 experimental.chat.system.transform 追加的内容
消息列表(messages)
├── 历史对话消息
├── [倒数第二] 合成 user part(plan/build-switch 提醒,若适用)
└── [最后] 若达到最大步数,追加一条 assistant 消息(max-steps 内容)
AGENTS.md 文件编写建议
AGENTS.md 是最常见的 instructions 文件,推荐结构:
markdown
# 项目规范
## 技术栈
- 语言:TypeScript
- 包管理:pnpm
- 测试:vitest
## 开发规范
- 提交前必须运行:`pnpm typecheck && pnpm lint`
- 不要在代码中添加注释,除非逻辑不自明
- 所有新文件必须有对应的单元测试
## 目录说明
- `src/` --- 主要源代码
- `packages/` --- 子包
- `docs/` --- 文档,不要自动生成
加载优先级与覆盖关系
shell
macOS MDM(最高)
> 全局 AGENTS.md(~/.config/opencode/AGENTS.md)
> 项目 AGENTS.md(项目根目录)
> config.instructions 中的额外文件
> 动态加载(read 工具触发)
多个文件叠加合并(不互相覆盖),均会出现在 System Prompt 中。
完整 System Prompt 示例
以下模拟一次真实调用,条件:
- 模型:
claude-sonnet-4-5(anthropic 提供商) - Agent:内置
build(无自定义 prompt) - Working directory:
/Users/mac/myproject/src,worktree 根:/Users/mac/myproject - 项目有
/Users/mac/myproject/AGENTS.md和/Users/mac/myproject/src/AGENTS.md - 全局有
~/.config/opencode/AGENTS.md - 配置了 1 个 skill:
commit
最终传给 LLM 的 system 数组(共 1 个字符串块,各部分用 \n 拼接):
sql
==== 第 1 块(system[0])====
【基础提示词 --- anthropic.txt】
You are OpenCode, the best coding agent on the planet.
You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.
If the user asks for help or wants to give feedback inform them of the following:
- ctrl+p to list available actions
- To give feedback, users should report the issue at
https://github.com/anomalyco/opencode
# Tone and style
- Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.
- Your output will be displayed on a command line interface. ...
# Professional objectivity
Prioritize technical accuracy and truthfulness over validating the user's beliefs. ...
# Task Management
You have access to the TodoWrite tools to help you manage and plan tasks. Use these tools VERY frequently ...
# Doing tasks
The user will primarily request you perform software engineering tasks. ...
# Tool usage policy
- When doing file search, prefer to use the Task tool in order to reduce context usage.
...
# Code References
When referencing specific functions or pieces of code include the pattern `file_path:line_number` ...
【环境信息 --- sys.environment()】
You are powered by the model named claude-sonnet-4-5. The exact model ID is anthropic/claude-sonnet-4-5
Here is some useful information about the environment you are running in:
<env>
Working directory: /Users/mac/myproject/src
Workspace root folder: /Users/mac/myproject
Is directory a git repo: yes
Platform: darwin
Today's date: Mon May 04 2026
</env>
【指令文件 --- instruction.system(),共 3 条】
Instructions from: /Users/mac/.config/opencode/AGENTS.md
遵循公司统一编码规范,所有 PR 必须经过 code review。
Instructions from: /Users/mac/myproject/src/AGENTS.md
src 目录使用 TypeScript strict 模式,禁止使用 any。
Instructions from: /Users/mac/myproject/AGENTS.md
禁止直接向 main 分支提交,必须通过 PR。
提交前运行:pnpm typecheck && pnpm lint
【技能列表 --- sys.skills()】
Skills provide specialized instructions and workflows for specific tasks.
Use the skill tool to load a skill when a task matches its description.
<available_skills>
<skill>
<name>commit</name>
<description>Use when the user asks to commit changes to git</description>
<location>file:///Users/mac/.config/opencode/skills/commit.md</location>
</skill>
</available_skills>
system[0]是以上所有内容用\n连接的单个字符串 ,这是 LLM API 接收到的完整 system prompt。若插件通过
experimental.chat.system.transform钩子追加了额外内容,则会出现system[1]、system[2]等。
源代码索引
| 文件 | 职责 |
|---|---|
packages/opencode/src/session/llm.ts |
最终组装 system 数组,触发 plugin 钩子 |
packages/opencode/src/session/prompt.ts |
准备 env/instructions/skills,管理对话循环 |
packages/opencode/src/session/system.ts |
environment() 和 skills() 实现;provider() 选择提示词文件 |
packages/opencode/src/session/instruction.ts |
AGENTS.md 查找、读取、动态注入逻辑 |
packages/opencode/src/session/prompt/anthropic.txt |
Claude 模型基础提示词 |
packages/opencode/src/session/prompt/default.txt |
其他模型默认提示词 |
packages/opencode/src/session/prompt/plan.txt |
plan agent 只读模式提醒 |
packages/opencode/src/session/prompt/build-switch.txt |
plan→build 切换提醒 |
packages/opencode/src/session/prompt/max-steps.txt |
达到最大步数时注入 |