想让大语言模型在项目里表现得像个"自己人",光靠通用的聪明还不够,它需要知道这个项目的独特脾气。OpenCode 的做法很直接:提供一套分层、可组合的规则机制,让团队把约定、架构、踩坑记录写成文件,模型每次会话都会自动"预习"一遍。这套机制的核心叫 AGENTS.md,但远不止于此。

从一张说明书开始:AGENTS.md
每一个 OpenCode 项目都可以在根目录放一个 AGENTS.md 文件,里面写的是专门给 LLM 看的行为指南。用过 Cursor 的人会发现这个概念非常熟悉------它就是 OpenCode 版的 Rules。
怎么开始呢?最简单的方法是打开 OpenCode 后执行 /init 命令。这个命令会干几件很贴心的事:它先扫描仓库里的重要文件,如果有些信息从代码本身看不出来,它会主动提一两个问题,最终生成或更新一份项目定制的 AGENTS.md。它不会空泛地堆砌模板,而是专注于未来所有 Agent 会话最可能反复用到的那些点:
- 构建、检查、测试的具体指令
- 当步骤顺序很重要时,明确的操作顺序和验证方式
- 光看文件名猜不出的架构布局和仓库结构
- 项目特定的约定、环境配置中的小机关、容易踩的坑
- 指向已有指令来源的引用(比如这套规范其实来自 Cursor 或 Copilot 的规则)
如果项目里已经有了一份 AGENTS.md,/init 会在原基础上改进,而不是粗暴覆盖。这种增量更新的思路,对长期维护的项目非常友好。
文件写好后,别忘了把它提交到 Git。因为这里面沉淀的是团队共识,本就该和代码一起被版本管理。
一个真实的例子
假设有一个 SST v3 的 monorepo 项目,使用 TypeScript 和 bun 工作空间,它的 AGENTS.md 可能长这样:
markdown
# SST v3 Monorepo Project
This is an SST v3 monorepo with TypeScript. The project uses bun workspaces for package management.
## Project Structure
- `packages/` - Contains all workspace packages (functions, core, web, etc.)
- `infra/` - Infrastructure definitions split by service (storage.ts, api.ts, web.ts)
- `sst.config.ts` - Main SST configuration with dynamic imports
## Code Standards
- Use TypeScript with strict mode enabled
- Shared code goes in `packages/core/` with proper exports configuration
- Functions go in `packages/functions/`
- Infrastructure should be split into logical files in `infra/`
## Monorepo Conventions
- Import shared modules using workspace names: `@my-app/core/example`
寥寥数语,就告诉了模型这个仓库哪里放什么、怎么导包、用什么类型系统,比让 AI 自己从几百个文件里猜要高效得多。
规则的层级:从项目到全域
OpenCode 支持把指令放在不同位置,每层有不同的覆盖范围,合在一起就构成了从个人到团队的完整约束体系。
项目级规则
最常接触的就是项目根目录下的 AGENTS.md。它只在操作这个目录及其子目录时生效,团队里的所有人共享同一份。
全局规则
还有一份全局规则,路径是 ~/.config/opencode/AGENTS.md。这份文件对这台机器上所有 OpenCode 会话都起作用。由于它不归 Git 管,也不会被分享给团队其他成员,这里特别适合放入纯个人的偏好------比如"我喜欢用分号结尾"或"永远不要用 any 类型"这类只属于自己的执念。
Claude Code 用户的平滑迁移
OpenCode 考虑到了从 Claude Code 迁过来的用户。如果某个项目里找不到 AGENTS.md,它会自动向后兼容,去读取 CLAUDE.md 作为项目规则。对应的全局规则后备是 ~/.claude/CLAUDE.md,另外连 ~/.claude/skills/ 目录下的技能文件也一并支持。
这种兼容不是永远开启的。如果团队不希望有任何混用,可以用环境变量精确控制:
bash
export OPENCODE_DISABLE_CLAUDE_CODE=1 # 禁用所有 .claude 支持
export OPENCODE_DISABLE_CLAUDE_CODE_PROMPT=1 # 仅禁用 ~/.claude/CLAUDE.md
export OPENCODE_DISABLE_CLAUDE_CODE_SKILLS=1 # 仅禁用 .claude/skills
在同时存在多个规则来源时,OpenCode 有一套明确的优先级逻辑:
- 从当前目录开始,沿着父目录一路向上找,最先找到的本地文件(
AGENTS.md或CLAUDE.md)生效。 - 全局文件里,
~/.config/opencode/AGENTS.md优先于~/.claude/CLAUDE.md。
简单说就是"近的盖远的,专用的盖通用的"。
引入外部规则文件,而不是复制粘贴
很多团队的规范已经写在 CONTRIBUTING.md、docs/guidelines.md,甚至 .cursor/rules/ 的多个 Markdown 里了。OpenCode 允许直接在 opencode.json 中声明这些文件,不必把内容再复制到 AGENTS.md 中。
json
{
"$schema": "https://opencode.ai/config.json",
"instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"]
}
路径支持 glob 模式,对 monorepo 里每个子包都有自己的 AGENTS.md 的场景尤其方便。同样的配置也可以用远程 URL,方便跨仓库复用一套中央规范:
json
{
"$schema": "https://opencode.ai/config.json",
"instructions": ["https://raw.githubusercontent.com/my-org/shared-rules/main/style.md"]
}
远程文件在拉取时有 5 秒超时限制,保证启动不会卡住。所有通过 instructions 声明的文件,最终都会和实体 AGENTS.md 的内容合并到一起喂给模型。
在 AGENTS.md 里手动教 AI 读文件
虽然 OpenCode 不会自动解析 AGENTS.md 里类似于 @docs/typescript-guidelines.md 的引用,但可以通过显式指令教会模型去读。比如这样写:
markdown
CRITICAL: When you encounter a file reference (e.g., @rules/general.md), use your Read tool to load it on a need-to-know basis. They're relevant to the SPECIFIC task at hand.
- Do NOT preemptively load all references - use lazy loading based on actual need
- When loaded, treat content as mandatory instructions that override defaults
- Follow references recursively when needed
## Development Guidelines
For TypeScript code style and best practices: @docs/typescript-guidelines.md
这等于是给了 LLM 一条死命令:看到 @ 开头的引用,就用 Read 工具按需加载,并且把里面的内容当作硬性规则。这种"懒加载指令"的好处是让 AGENTS.md 保持精简,详细的规范文件独立维护,甚至可以跨项目用符号链接或 git 子模块共享。
不过,对于 monorepo 或团队里标准文件已经很多的项目,更推荐用 opencode.json 的 instructions 字段配合 glob 模式(比如 "packages/*/AGENTS.md")。这比在 AGENTS.md 里手动罗列引用要干净得多,也更不容易遗漏。
归根结底,OpenCode 的这套规则系统做的是一件事:把散落在团队维基、代码注释、老员工脑子里的隐性知识,翻译成 LLM 每次干活前都能读到的显性指令。操作不复杂,但效果直接决定了 AI 写出来的是"能跑的代码"还是"符合这个项目灵魂的代码"。