概述

AGENTS.md 是 Codex 的项目级指令文件,用于向模型传递用户自定义的编码规范、项目说明、构建步骤等指导信息。系统会沿目录层级发现并加载这些文件,将其序列化后注入对话上下文,并在 compaction 时正确过滤和重新注入。


1. 文件发现:discover_project_doc_paths()

文件core/src/project_doc.rs:207

1.1 发现算法

  1. 从当前工作目录(config.cwd向上遍历,寻找 project_root_markers(默认为 .git)标识的项目根目录
  2. 收集从项目根到当前工作目录路径上每个目录中的 AGENTS.md 文件
  3. 不会遍历超过项目根目录
  4. 如果没有找到项目根标记,只搜索当前工作目录

1.2 文件优先级

每个目录下按以下顺序搜索,找到第一个即停止candidate_filenames(),第 294 行):

优先级 文件名 说明
1 AGENTS.override.md 本地覆盖,不纳入版本控制
2 AGENTS.md 标准项目文档,通常纳入版本控制
3 config.project_doc_fallback_filenames 中的文件 额外配置的备选文件名

1.3 关键常量

pub const DEFAULT_PROJECT_DOC_FILENAME: &str = "AGENTS.md";
pub const LOCAL_PROJECT_DOC_FILENAME: &str = "AGENTS.override.md";

2. 文件加载:read_project_docs()

文件core/src/project_doc.rs:149

2.1 加载流程

  1. 检查 project_doc_max_bytes 配置,为 0 则直接返回 None
  2. 调用 discover_project_doc_paths() 获取文件列表
  3. 按顺序逐个读取文件,用 remaining 变量跟踪剩余字节预算
  4. 超出预算的文件会被截断并打印警告日志
  5. 将所有非空文件内容用 "\n\n" 连接返回

2.2 拼接顺序

从项目根目录到当前工作目录,例如:

<项目根/AGENTS.md 内容>

<子目录/AGENTS.md 内容>

<当前目录/AGENTS.md 内容>

3. 内容组装:get_user_instructions()

文件core/src/project_doc.rs:81

这是最终组装 user_instructions 的入口函数,将多种内容拼接成一个完整字符串:

config.user_instructions          // 用户直接配置的指令
--- project-doc ---
<AGENTS.md 内容>                  // read_project_docs() 的结果
<JS REPL 指令>                    // 如果启用了 JsRepl feature
<插件能力摘要>                     // render_plugins_section()
<Skills 文档>                     // render_skills_section()
<层级代理说明>                     // 如果启用了 ChildAgentsMd feature

各部分之间用 "\n\n"PROJECT_DOC_SEPARATOR"\n\n--- project-doc ---\n\n")分隔。


4. 序列化与包装

文件core/src/instructions/user_instructions.rs

4.1 UserInstructions 结构体

pub(crate) struct UserInstructions {
    pub directory: String,   // 当前工作目录路径
    pub text: String,        // get_user_instructions() 返回的完整内容
}

4.2 序列化格式

serialize_to_text() 将内容包装为带首尾标记的格式:

# AGENTS.md instructions for /path/to/project

<INSTRUCTIONS>
...实际内容...
</INSTRUCTIONS>

4.3 转换为 ResponseItem

通过 AGENTS_MD_FRAGMENT.into_message() 转为 user role 的 ResponseItem

impl From<UserInstructions> for ResponseItem {
    fn from(ui: UserInstructions) -> Self {
        AGENTS_MD_FRAGMENT.into_message(ui.serialize_to_text())
    }
}

首尾标记是后续 compaction 过滤时识别该消息的关键依据。


5. 注入对话上下文

文件core/src/codex.rs:3124

注入发生在 build_initial_context() 中,将序列化后的内容作为 user role 消息加入 contextual_user_sections

if let Some(user_instructions) = turn_context.user_instructions.as_deref() {
    contextual_user_sections.push(
        UserInstructions {
            text: user_instructions.to_string(),
            directory: turn_context.cwd.to_string_lossy().into_owned(),
        }
        .serialize_to_text(),
    );
}

5.1 注入时机

场景 触发条件
新会话启动 InitialHistory::Newreference_context_item 初始为 None
恢复会话 InitialHistory::Resumed,重建历史后追加
Compaction 之后 reference_context_item 被重置为 None

5.2 正常多轮对话

reference_context_itemSome 时走增量路径 build_settings_update_items()不会重复注入 AGENTS.md 内容。


6. Compaction 过滤

Compaction 时需要确保 AGENTS.md 内容不被压缩模型改写,分三层处理。

6.1 第一层:按 role 丢弃 developer 消息

文件core/src/compact_remote.rs:190

fn should_keep_compacted_history_item(item: &ResponseItem) -> bool {
    match item {
        ResponseItem::Message { role, .. } if role == "developer" => false,
        // ...
    }
}

6.2 第二层:识别并丢弃伪用户消息

文件core/src/contextual_user_message.rs

AGENTS.md 内容以 user role 注入,通过首尾标记匹配来识别:

pub(crate) const AGENTS_MD_START_MARKER: &str = "# AGENTS.md instructions for ";
pub(crate) const AGENTS_MD_END_MARKER: &str = "</INSTRUCTIONS>";

is_contextual_user_fragment() 检查文本是否同时以开始标记开头、结束标记结尾。匹配成功则 parse_turn_item() 返回 None,该消息被 should_keep_compacted_history_item() 过滤掉。

完整的伪用户消息类型列表:

Fragment 类型 开始标记 结束标记
AGENTS.md 指令 # AGENTS.md instructions for </INSTRUCTIONS>
环境上下文 <environment_context> </environment_context>
Skills <skill> </skill>
Shell 命令 <user_shell_command> </user_shell_command>
Turn 中止 <turn_aborted> </turn_aborted>
Subagent 通知 <subagent_notification> </subagent_notification>

6.3 第三层:重新注入

过滤完成后 reference_context_item 被置为 None,下一个 turn 自动走 build_initial_context() 全量路径,从内存中的 user_instructions 重新注入最新内容。


7. Hierarchical Agents 层级规则

Feature FlagFeature::ChildAgentsMd(默认关闭)

模板文件core/hierarchical_agents_message.md

启用后在 get_user_instructions() 末尾追加层级说明,核心规则:

  1. AGENTS.md 管辖其所在目录及所有子目录
  2. 修改文件时必须遵守所有覆盖该文件的 AGENTS.md
  3. 深层目录的 AGENTS.md 覆盖上层的同名指令
  4. 用户/系统/开发者在 prompt 中直接给出的指令优先级高于任何 AGENTS.md

即使项目中没有 AGENTS.md 文件,该说明也会被追加。


8. CLAUDE.mdAGENTS.md 迁移

文件core/src/external_agent_config.rs

处理从 Claude Code 迁移到 Codex 的场景。

8.1 检测源文件

find_repo_agents_md_source() 按顺序检查:

<repo_root>/CLAUDE.md
<repo_root>/.claude/CLAUDE.md

Home 目录级别检查 ~/.claude/CLAUDE.md

8.2 迁移逻辑

import_agents_md() 的流程:

  1. 找到源 CLAUDE.md 文件
  2. 确认目标 AGENTS.md 不存在或为空(不覆盖已有文件)
  3. 调用 rewrite_and_copy_text_file() 复制并重写内容

8.3 术语重写

rewrite_claude_terms() 执行大小写不敏感的词边界替换:

原始术语 替换为
claude.md AGENTS.md
claude code / claude-code / claude_code / claudecode / claude Codex

替换使用词边界检测(is_word_byte),避免误替换单词内部的匹配。


9. 配置项

文件core/src/config/mod.rs

配置项 类型 默认值 说明
project_doc_max_bytes usize PROJECT_DOC_MAX_BYTES AGENTS.md 总字节数上限,超出截断
project_doc_fallback_filenames Vec<String> [] AGENTS.md 外额外搜索的备选文件名
project_root_markers Vec<String> [".git"] 项目根目录标识

10. 关键文件索引

文件 职责
core/src/project_doc.rs 文件发现、加载、内容组装
core/src/instructions/user_instructions.rs 序列化与包装(加首尾标记)
core/src/codex.rs 注入对话上下文、全量/增量判断
core/src/contextual_user_message.rs 伪用户消息标记定义与识别
core/src/compact_remote.rs Compaction 后过滤逻辑
core/src/external_agent_config.rs CLAUDE.mdAGENTS.md 迁移
core/hierarchical_agents_message.md 层级规则说明模板
core/src/context_manager/updates.rs 增量 diff 更新逻辑
core/src/context_manager/history.rs reference_context_item 状态管理

11. 完整流程图

文件系统                      内存                          对话上下文
─────────                   ────                          ────────
AGENTS.override.md ─┐
AGENTS.md ──────────┤
(多层目录)           │
                    ▼
          discover_project_doc_paths()
                    │
                    ▼
           read_project_docs()          ──→ 拼接多文件内容
                    │
                    ▼
         get_user_instructions()        ──→ 组合 config.instructions
                    │                       + AGENTS.md
                    │                       + plugins/skills
                    │                       + hierarchical message
                    ▼
          存入 Session.user_instructions(会话期间不变)
                    │
                    ▼
     ┌──────────────┴──────────────┐
     │                             │
  全量注入                       增量更新
  (reference_context_item        (reference_context_item
   == None)                       == Some)
     │                             │
     ▼                             ▼
  build_initial_context()     build_settings_update_items()
     │                        (不含 AGENTS.md,只含配置 diff)
     ▼
  UserInstructions::serialize_to_text()
     │
     ▼
  包装为带标记的 user role 消息:
  "# AGENTS.md instructions for ..."
  "...</INSTRUCTIONS>"
     │
     ▼
  注入对话 ──→ 模型可见

     ║
     ║ Compaction 时
     ▼
  should_keep_compacted_history_item()
     │
     ├─ developer 消息 → 丢弃
     ├─ 匹配标记的 user 消息 → 丢弃
     └─ 真实用户消息 → 保留
     │
     ▼
  reference_context_item = None
     │
     ▼
  下一 turn → 重新全量注入(最新内容)