Zed Agent Instructions 机制详解:AGENTS.md 与项目指令文件的配置、优先级与底层加载原理
本文基于 Zed 官方文档 instructions.md 展开,系统讲解 Zed Agent 的"始终在线"指令(Instructions)机制:个人级 ~/.config/zed/AGENTS.md 与项目级指令文件的配置方式、九种兼容文件的匹配优先级、旧 Rules 的迁移路径,并结合 agent、prompt_store、agent_settings、paths 等 crate 的源码,剖析指令文件是如何被加载、热更新并最终注入系统提示词的。读完后你既能正确配置各类指令文件,也能在源码层面验证其行为。
Instructions 是什么
Instructions 是 Zed Agent 的"always-on context"(始终在线上下文):其中的内容会被加入每一次相关 agent 交互的系统提示词中,适合放置需要在每次对话中都生效的持久化指导——仓库约定、偏好的语气、项目约束、编码规范等。
Zed 明确支持 AGENTS.md 开放约定(见文档 AGENTS.md 生态说明)作为个人级和项目级指令的主文件格式。与 Instructions 互补的是 Skills:当你需要的是"可按名调用、可复用"的任务级指令(如代码评审清单、发布流程)时,应使用 Skills 而不是把内容堆进指令文件。
| 使用场景 | 最适合 | 典型例子 |
|---|---|---|
| Instructions | 始终在线的指导 | 仓库约定、偏好语气、项目约束 |
| Skills | 可复用的任务工作流 | 代码评审清单、发布流程、迁移助手 |
个人指令(Personal Instructions)
个人指令对你用 Zed Agent 打开的每一个项目都生效。配置文件路径为:
~/.config/zed/AGENTS.md
在 Windows 上对应文件为 %APPDATA%\Zed\AGENTS.md。
源码级路径定义与显示形式的差异
实际路径由 paths crate 的 agents_file() 定义:
pub fn agents_file() -> &'static PathBuf {
static AGENTS_FILE: OnceLock<PathBuf> = OnceLock::new();
AGENTS_FILE.get_or_init(|| config_dir().join("AGENTS.md"))
}
即基于 config_dir() 拼接 AGENTS.md。源码注释还特意说明了一个容易被忽略的细节:面向用户展示的 ~/.config/zed/AGENTS.md(Windows 为 %APPDATA%\Zed\AGENTS.md)只是典型位置——如果设置了 XDG_CONFIG_HOME,或运行在 Flatpak 沙箱中,运行时的真实路径会与展示字符串不同(见 GLOBAL_AGENTS_FILE_DISPLAY 注释)。因此排查"个人指令为什么不生效"时,应以运行时配置目录为准。
加载与热更新:UserAgentsMd 全局状态机
个人指令的读取与监听逻辑集中在 user_agents_md.rs,核心是一个三态枚举:
pub enum UserAgentsMdState {
/// 文件缺失、为空或仅含空白字符
Empty,
/// 加载成功,携带 trim 后的内容
Loaded(SharedString),
/// 文件存在但读取失败,携带错误信息
Error(SharedString),
}
几个可验证的实现细节:
- 空文件等同于没有个人指令:内容会先
trim,纯空白被归为Empty(模块级文档注释与测试empty_file_is_ignored均有覆盖,见 测试代码)。 - 文件变化即时生效:通过
watch_config_file监听该文件,每次变化后重新读取并更新全局状态;测试reacts_to_file_changes验证了内容从first改为second后全局状态同步更新。 - 区分"文件不存在"与"读取失败":由于底层 watcher 对打开失败会吞掉错误并返回空串,实现中对每次事件额外调用
probe_read_error探测,只有NotFound才视为Empty,其余 IO 错误进入Error状态并通过回调暴露给宿主 UI,走与 settings/keymap 错误相同的提示路径(见 probe_read_error)。 - 读取是全量读取:模块注释明确说明"文件被完整读取,与原生 agent 加载项目 rules / 仓库 AGENTS.md 的方式一致",没有截断逻辑。
项目指令(Project Instructions)
项目指令文件只对当前项目生效。Zed 按固定顺序检查以下候选文件,只取第一个匹配到的文件:
.rules.cursorrules.windsurfrules.clinerules.github/copilot-instructions.mdAGENT.mdAGENTS.mdCLAUDE.mdGEMINI.md
优先级列表的源码定义
这个顺序在 prompt_store 的 prompts.rs 中以常量固化:
pub const RULES_FILE_NAMES: &[&str] = &[
".rules",
".cursorrules",
".windsurfrules",
".clinerules",
".github/copilot-instructions.md",
"AGENT.md",
"AGENTS.md",
"CLAUDE.md",
"GEMINI.md",
];
agent.rs 进一步将其惰性转换为相对路径列表 RULES_FILE_REL_PATHS,供工作树扫描使用。
"第一个匹配"的匹配逻辑
真正的选择逻辑在 load_worktree_rules_file:
let selected_rules_file = RULES_FILE_REL_PATHS
.iter()
.filter_map(|name| {
worktree
.entry_for_path(name)
.filter(|entry| entry.is_file())
.map(|entry| entry.path.clone())
})
.next(); // 只取第一个命中的条目
由此得到几个关键事实:
- 每个工作树(worktree)只会加载一份指令文件:命中即停,列表顺序即优先级。同一个项目里若同时存在
.cursorrules和AGENTS.md,只有.cursorrules会被 Zed Agent 读取。 - 必须是文件:
entry.is_file()过滤意味着目录不算命中。源码中有一条值得注意的注释——Cline 社区存在把.clinerules作为目录使用的做法,但 Zed 目前不支持("这在 GitHub 仓库中并不常见")。 - 多工作树项目:
ProjectContext持有worktrees: Vec<WorktreeContext>,每个工作树独立携带自己的rules_file,即一个项目添加多个工作树时,各自的项目指令都可以进入上下文(见 ProjectContext 结构)。 - 内容经 trim 后注入:读取结果来自项目 buffer 的 rope,注入前会
trim(agent.rs 第 1341-1345 行),与个人指令的处理方式一致。 - 文件变动触发上下文刷新:
handle_project_event监听工作树条目更新,当变更路径命中任一RULES_FILE_REL_PATHS(或 AGENTS 目录前缀)时,发送刷新信号重新构建项目上下文——修改项目指令文件后无需重启 Zed。
冲突时的覆盖规则
当项目指令与个人 AGENTS.md 内容冲突时,项目指令胜出。这一点不仅写在文档中,也直接体现在系统提示词模板里(见下文"指令如何进入系统提示词"一节中 "Project Rules ... take precedence over the personal AGENTS.md" 的措辞)。
指令文件支持情况对照
不同入口(Zed Agent / 外部 Agent / Terminal Threads)对同一批指令文件的支持并不相同,原文档给出的对照表如下:
| 文件 | Zed Agent | 外部 Agent | Terminal Threads |
|---|---|---|---|
~/.config/zed/AGENTS.md |
作为个人指令加载 | 通常不使用 | CLI 若读取则使用 |
项目 AGENTS.md |
作为项目指令加载 | 取决于具体 agent | 取决于具体 CLI |
CLAUDE.md |
作为兼容的项目指令被 Zed Agent 加载 | Claude 原生读取 | Claude Code CLI 原生读取 |
.github/copilot-instructions.md |
作为兼容的项目指令被 Zed Agent 加载 | 取决于具体 agent | 取决于具体 CLI |
需要牢记的一条边界:外部 Agent(External Agents)和 Terminal Threads 会直接读取它们各自原生的指令文件,Zed 的指令加载器并不控制这些 agent 的行为。换言之,上表中"取决于 agent / CLI"的情形下,行为由对应的外部工具(如 Claude Code CLI、Copilot 等)决定,不能假设 Zed 的九文件优先级同样适用于它们。外部 Agent 的具体接入方式参见 external-agents.md 与 terminal-threads.md。
指令如何进入系统提示词
个人与项目指令最终都由 Handlebars 模板 system_prompt.hbs 组装进系统提示词,模板中有一个 User's Custom Instructions 区块:
{{#if (or user_agents_md has_rules)}}
## User's Custom Instructions
The following additional instructions are provided by the user ...
{{#if user_agents_md}}
### Personal `AGENTS.md`
These instructions apply to every project this user opens. Project-specific rules below may override them.
{{{user_agents_md}}}
{{/if}}
{{#if has_rules}}
### Project Rules
These instructions are scoped to the current project. They take precedence over the personal `AGENTS.md` above when they conflict.
...
{{/if}}
{{/if}}
```
从模板结构可以确认:个人指令与项目指令是**同时注入**(而非二选一)的两个子区块,覆盖语义通过模板文案显式传达给模型;`has_rules` / `has_skills` 这类派生标志位在 [ProjectContext](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/prompt_store/src/prompts.rs?utm_source=gitcode_repo_files#L34-L85) 中维护,注释解释了原因——Handlebars 无法直接对集合做 `is_empty` 判断,所以由 Rust 侧同步维护布尔标志。
以本仓库自身为例,根目录就放着 [AGENTS.md](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/AGENTS.md?utm_source=gitcode_repo_files)、[CLAUDE.md](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/CLAUDE.md?utm_source=gitcode_repo_files) 和 [GEMINI.md](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/GEMINI.md?utm_source=gitcode_repo_files):在 Zed 中打开本仓库开发时,按上文优先级只会命中 `AGENTS.md`;而 `CLAUDE.md`、`GEMINI.md` 则留给 Claude、Gemini 等各自工具原生读取——这正是"兼容多种生态指令文件"设计的实际体现。
## 从 Rules 迁移到 Skills / Instructions
Zed 已用 **Skills + Instructions** 取代了旧的 Rules 机制,迁移路径为(详见 [rules.md](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/docs/src/ai/rules.md?utm_source=gitcode_repo_files)):
- **可复用、按需触发**的 Rules → 迁移为 [Skills](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/docs/src/ai/skills.md?utm_source=gitcode_repo_files)(`SKILL.md` 形式的可命名调用任务);
- **默认始终生效**的 Rules → 迁移为个人 `AGENTS.md`;
- 项目中的 `.rules` 文件 → 继续作为兼容项目指令文件被支持(对应上文优先级列表第一项)。
仓库中也保留了相应的迁移工具:[rules_to_skills_migration.rs](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/prompt_store/src/rules_to_skills_migration.rs?utm_source=gitcode_repo_files) 负责旧 Rules 到新 Skills 的转换,说明"Rules"这一命名在内部代码中仍作为历史包袱被维护,但对用户而言新的心智模型就是"Instructions 管全局、Skills 管任务"。
## 小结
- 个人指令写入 `~/.config/zed/AGENTS.md`(Windows 为 `%APPDATA%\Zed\AGENTS.md`),全量读取、trim 后注入,文件修改后自动热更新;空文件等价于未配置。
- 项目指令按 `.rules` → `.cursorrules` → `.windsurfrules` → `.clinerules` → `.github/copilot-instructions.md` → `AGENT.md` → `AGENTS.md` → `CLAUDE.md` → `GEMINI.md` 的顺序匹配,**每个工作树只取第一个命中的文件**,且冲突时覆盖个人指令。
- 指令与 Skills 的分工是"always-on 指导" vs "按名调用的任务工作流",旧 Rules 按此二分迁移。
- 所有关键行为(优先级常量、首个命中逻辑、热刷新、模板注入、三态加载状态)均可在 [crates/prompt_store/src/prompts.rs](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/prompt_store/src/prompts.rs?utm_source=gitcode_repo_files)、[crates/agent/src/agent.rs](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/agent/src/agent.rs?utm_source=gitcode_repo_files)、[crates/agent_settings/src/user_agents_md.rs](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/agent_settings/src/user_agents_md.rs?utm_source=gitcode_repo_files)、[crates/agent/src/templates/system_prompt.hbs](https://gitcode.com/GitHub_Trending/ze/zed/blob/b1a7ef0cf66dfbf9d7661170c96d97c7df916c68/crates/agent/src/templates/system_prompt.hbs?utm_source=gitcode_repo_files) 中直接验证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00