首页
/ Zed Agent Instructions 机制详解:AGENTS.md 与项目指令文件的配置、优先级与底层加载原理

Zed Agent Instructions 机制详解:AGENTS.md 与项目指令文件的配置、优先级与底层加载原理

2026-09-06 14:54:23作者:董灵辛Dennis

本文基于 Zed 官方文档 instructions.md 展开,系统讲解 Zed Agent 的"始终在线"指令(Instructions)机制:个人级 ~/.config/zed/AGENTS.md 与项目级指令文件的配置方式、九种兼容文件的匹配优先级、旧 Rules 的迁移路径,并结合 agentprompt_storeagent_settingspaths 等 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 按固定顺序检查以下候选文件,只取第一个匹配到的文件

  1. .rules
  2. .cursorrules
  3. .windsurfrules
  4. .clinerules
  5. .github/copilot-instructions.md
  6. AGENT.md
  7. AGENTS.md
  8. CLAUDE.md
  9. GEMINI.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)只会加载一份指令文件:命中即停,列表顺序即优先级。同一个项目里若同时存在 .cursorrulesAGENTS.md,只有 .cursorrules 会被 Zed Agent 读取。
  • 必须是文件entry.is_file() 过滤意味着目录不算命中。源码中有一条值得注意的注释——Cline 社区存在把 .clinerules 作为目录使用的做法,但 Zed 目前不支持("这在 GitHub 仓库中并不常见")。
  • 多工作树项目ProjectContext 持有 worktrees: Vec<WorktreeContext>,每个工作树独立携带自己的 rules_file,即一个项目添加多个工作树时,各自的项目指令都可以进入上下文(见 ProjectContext 结构)。
  • 内容经 trim 后注入:读取结果来自项目 buffer 的 rope,注入前会 trimagent.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.mdterminal-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) 中直接验证。
登录后查看全文
热门项目推荐
相关项目推荐