上一篇:Approval 与 Sandbox:写入审批和工作区边界
下一篇:Mini Harness Recap:14 天架构复盘
English version: AGENTS.md for AI Coding Agents: Load Project Rules into LLM Context
文章介绍
Day 12 解决了 agent “能不能执行”和“可以影响哪里”的问题。今天处理另一个长期存在的工程问题:agent 如何知道每个项目自己的约定?
同一个模型进入不同代码库时,可能需要遵循完全不同的规则:
- 使用 npm、pnpm 还是 bun。
- 修改后运行哪个 typecheck 或 test 命令。
- 哪些目录是生成代码,不能手动编辑。
- 应该复用哪些项目内部 API。
- 提交代码前需要满足哪些检查。
这些信息不适合每次都由用户重新输入。更合理的方式是把它们放进代码库中的 durable project guidance,例如根目录的 AGENTS.md,由 harness 在每次运行开始时自动发现并注入模型上下文。

今天要解决什么
今天完成六个交付:
- 从 workspace 根目录读取
AGENTS.md。 - 为规则内容设置字节上限,避免永久挤占 context window。
- 把项目规则注入 system prompt。
- 用独立的
rulescontext kind 记录规则来源和 token 占用。 - 为 CLI 增加
--workspace,方便在独立项目根目录运行 harness。 - 提供不会影响主仓库规则的 Day 13 fixture workspace。
运行演示:
npm run dev -- --workspace demos/day-13/workspace --context-report "load project rules"
它在 Cursor/Codex 里对应哪一层
今天实现的是 Project Guidance / Durable Rules Layer。
它位于 context builder 和 model provider 之间:
workspace root
-> discover AGENTS.md
-> validate workspace path
-> read with size limit
-> add to system context
-> report rules token usage
-> model decides
项目规则不是一次性的聊天消息。它们会随着代码库一起版本管理,让团队成员和 coding agent 共享相同的工程约定。
为什么需要项目规则
1. 模型的通用能力不知道本地约定
模型可能知道 TypeScript、React 或 Node.js,但它不知道这个仓库是否要求:
Use npm workspaces.
Never edit generated files.
Run npm run typecheck before completion.
Prefer repository helpers over new dependencies.
这些规则来自项目,而不是来自通用训练知识。
2. README 和 AGENTS.md 职责不同
README 通常面向人类读者,介绍项目用途、安装和使用方式。AGENTS.md 更适合记录 agent 执行任务时需要遵守的约束。
两者可能有重叠,但关注点不同:
| 文件 | 主要读者 | 典型内容 |
|---|---|---|
README.md |
用户与贡献者 | 项目介绍、安装、使用 |
AGENTS.md |
Coding agent | 编辑边界、测试命令、代码规范 |
3. Rules 不等于 Safety
规则可能写着“不要修改 migrations”,但这仍然是一条模型指导,不是不可绕过的权限边界。
真正的执行路径仍然需要 Day 12 的安全层:
project rules guide behavior
approval authorizes side effects
sandbox limits reachable paths
三者不能互相替代。
设计思路
1. 第一版只读取根目录 AGENTS.md
大型 monorepo 可能需要目录级规则:根目录定义通用约定,子目录覆盖局部规则。
Day 13 先实现最小、可预测的版本:
workspace/AGENTS.md -> active
workspace/apps/AGENTS.md -> not loaded yet
只支持 root-level guidance 可以避免过早引入规则继承、优先级和冲突合并。
2. 缺失规则不是错误
并不是每个仓库都有 AGENTS.md。加载器在文件不存在时返回空结果:
{
content: "",
bytes: 0,
returnedBytes: 0,
truncated: false
}
Context builder 会明确记录:
No root AGENTS.md project rules were found.
这样调试时可以区分“没有规则”和“加载器没有运行”。
3. 规则必须有长度上限
项目规则会进入每一次模型调用。如果文件无限增长,它会持续占用 context window,并增加延迟和成本。
Day 13 默认最多读取:
const DEFAULT_MAX_RULE_BYTES = 16_000;
超过上限时返回 truncated: true,并在 system prompt 中标记 (truncated)。
4. Rules 作为独立 ContextPart
Day 09 的 Context Explorer 已经支持按 kind 汇总 token。共享类型中也提前定义了:
type ContextKind =
| "system"
| "tools"
| "rules"
| "files"
| "conversation"
| "tool-results";
Day 13 把规则作为独立 part,而不是只把文本拼进 system prompt 后失去来源信息。
实现步骤
1. 实现规则加载器
文件:apps/mini-harness/src/rules/loader.ts
加载器返回内容、来源和截断信息:
export type LoadedProjectRules = {
content: string;
source?: string;
bytes: number;
returnedBytes: number;
truncated: boolean;
};
读取前复用 Day 12 的 workspace guard:
const rulePath = await resolveWorkspacePath(workspaceRoot, "AGENTS.md");
const buffer = await readOptionalFile(rulePath.absolutePath);
虽然文件名是固定的,这个校验仍然让规则加载与其他 workspace 文件访问保持同一安全边界。
2. 区分文件缺失和真实读取错误
加载器只把 ENOENT 当成“没有规则”:
if (isFileNotFound(error)) {
return undefined;
}
throw error;
权限错误、I/O 错误不应该静默降级,否则用户会误以为规则已经生效。
3. 注入 Context Builder
文件:apps/mini-harness/src/context/builder.ts
构建上下文时并行概念上包含这些来源:
system instructions
project rules
history summary
tool definitions
selected project snippets
user request
System prompt 中新增:
Project rules:
--- AGENTS.md ---
...repository guidance...
同时增加一个可观测的 part:
{
label: "Project rules",
kind: "rules",
source: projectRules.source ?? "not-found",
content: projectRulesContext,
}
4. Context Explorer 自动显示规则成本
不需要修改 Context Explorer 的统计逻辑。因为它本来就根据 ContextPart.kind 分组,新增 part 后会自动产生:
rules ~62 tokens 2.3% 1 part
并在 All parts 中显示:
Project rules rules ~62 tokens source: AGENTS.md
5. 增加 workspace 参数
文件:apps/mini-harness/src/cli.ts
CLI 新增:
--workspace <path>
这个目录同时成为:
- 文件工具根目录。
- Git 工具根目录。
- Patch sandbox 根目录。
- Context snippets 根目录。
- Project rules 查找根目录。
因此规则和工具不会使用不同的 workspace 定义。
6. 创建独立 demo workspace
文件:demos/day-13/workspace/AGENTS.md
Demo 规则包括:
- Use TypeScript strict mode for source code.
- Prefer focused patches over whole-file rewrites.
- Run the typecheck command before reporting completion.
- Keep generated files out of source directories.
把 fixture 放在 demos/day-13/workspace,可以验证规则加载,又不会在仓库根目录创建一份会影响整个项目的真实 agent 指令。
Demo
运行:
npm run dev -- --workspace demos/day-13/workspace --context-report "load project rules"
Mock provider 会返回:
The root `AGENTS.md` rules were loaded into the system context before model execution.
Context Explorer 的关键输出:
By kind
rules ~62 tokens 2.3% 1 part
All parts
Project rules rules ~62 tokens source: AGENTS.md
具体 token 数会随着工具定义和规则内容变化,重点是 rules 有独立的来源和预算占比。
当前系统能力变化
Day 13 后,一次运行的完整输入链路变成:
workspace root
-> AGENTS.md rules
-> selected project snippets
-> tool definitions
-> history + user task
-> model decision
-> approval + sandbox
-> tool execution
-> transcript + context report
Mini harness 不再只理解代码内容,还能带着项目约定执行任务。
遇到的问题
1. 规则优先级怎么处理
当前实现把根规则放入 system prompt,并明确要求它们不能覆盖更高优先级指令。生产系统还需要定义 system、developer、user、project rules 和目录规则之间的完整优先级。
2. AGENTS.md 是否可信
加载器假设 workspace 是用户选择并信任的代码库。来自未知仓库的规则可能包含 prompt injection,因此真实产品应在打开不可信项目时显示来源,并限制规则能够影响的工具权限。
3. 为什么不用工具临时读取规则
如果依赖模型自己调用 read_file,模型可能忘记读取,也可能在做出第一次决策后才发现规则。
规则属于运行初始化上下文,应该由 harness 确定性加载。
4. 为什么暂不支持嵌套规则
目录级规则需要回答:
- 根据当前任务还是目标文件选择规则?
- 多个规则文件如何合并?
- 子目录规则能否覆盖根规则?
- 删除或移动文件时使用哪个目录的规则?
这些问题值得单独设计,不适合塞进最小 root loader。
明天做什么
Day 14 将完成 Mini Harness Recap。
我们会串联 14 天的能力,回顾从 context、tools、agent loop 到 patch、approval、rules 和 observability 的完整架构,并给出下一阶段的扩展边界。
Comments