Skip to main content

本页解决什么问题

接手一个陌生代码库时,最危险的第一步不是“不会写代码”,而是还没有形成系统模型,就开始改代码。你可能看到了一个报错文件,却不知道它由哪个入口触发;看到了一个函数,却不知道哪些调用方依赖它;看到了一个测试,却不知道它覆盖的是哪条业务路径。 本页只讲一件事:如何让 Codex 在只读边界内,从目录结构走到入口,再沿调用链走到测试映射,最后输出一份可供人核对的探索报告。 这里的“只读”是行为边界,不是让 Codex 少读几个文件。探索阶段可以广泛读取、搜索、运行不会改变项目状态的检查命令,但不修改源代码、测试、配置、依赖或生成物。等你确认了范围和事实,再决定是否切换到计划或实施工作流。 你将学会:
  • 如何先确认工作区、规则文件和项目入口。
  • 如何从目录结构筛出真正值得阅读的文件。
  • 如何找到 Web、CLI、任务队列和脚本等不同类型的入口。
  • 如何用符号搜索和证据逐段追踪调用链。
  • 如何把生产代码映射到测试文件、测试命令和缺失覆盖。
  • 如何编写 Codex 探索提示词,让它报告证据而不是猜测。
  • 什么时候继续只读探索,什么时候切入计划模式。
  • 如何识别“目录摘要很漂亮但结论不可靠”等常见错误。
  • 如何用一个真实项目演练完整的目录到测试映射流程。
本页使用的 Codex 命令和界面可能随版本变化。运行前以本机的 codex --help、相关子命令的 --help 和官方文档为准。参考资料:参考/codex/02-core-concepts.md、参考/codex/14-workflows.md、参考/codex/11-agents-md.md。

先定边界:探索不是实现

“帮我了解这个项目”和“帮我修复登录问题”是两种不同任务。前者的产物是地图、证据和未知项;后者的产物是修改和验证。把两者混在一个会话里,Codex 很容易在你还没确认根因时提出并执行改动。 探索阶段的目标可以写成四个问题: 在提示词中明确以下非目标:

只读不等于盲目禁止命令

可以使用的证据命令通常包括:
  • pwd、git rev-parse --show-toplevel:确认当前位置和项目根。
  • git status --short --branch:确认工作区状态,不修改文件。
  • find 或 rg --files:列目录和文件,不读取文件内容到磁盘。
  • rg:搜索路由、符号、命令、测试名和配置键。
  • git log、git blame:了解变更背景和责任边界。
  • 项目已有的 lint、typecheck、测试收集或构建信息命令,前提是它们不会写入工作区。
需要先确认再运行的命令包括:
  • npm install、pnpm install、pip install、go generate 等可能改变依赖或生成文件的命令。
  • 需要联网、访问云服务、读取生产数据或发送请求的命令。
  • 会生成缓存、覆盖快照、写报告或启动长期运行服务的命令。
  • git clean、批量删除、迁移、格式化和自动修复命令。
“只读”不是只看 Codex 的总结。你要看它实际执行的命令和输出,并用 git status、git diff --stat 证明没有意外改动。

第一步:确定工作区和起点

不要从聊天上下文中猜项目根。先让终端给出证据,再启动 Codex,或者在会话里明确要求它执行同样的检查。

终端基线检查

在目标项目目录执行:
Windows PowerShell 可以使用:
记录以下基线:
  • Codex 实际工作的绝对路径。
  • Git 根目录,而不是编辑器当前打开的子目录。
  • 当前分支和已有未提交修改。
  • 项目使用的语言、包管理器和主要构建工具。
  • 是否存在 AGENTS.md、AGENTS.override.md 或配置中声明的备选规则文件。
已有未提交修改属于工作区事实。探索报告应把它们列为背景,不要把它们当成你本轮的结论,也不要为了“干净”而恢复或覆盖。

启动只读 Codex

先查看本机支持的参数:
具体版本支持的只读参数可能不同。若本机支持沙箱参数,可以在启动时使用只读模式:
也可以进入会话后查看权限菜单,根据本机界面切换到只读配置。参考资料中强调,沙箱和审批是两个维度:沙箱决定能否越过文件或网络边界,审批决定何时停下来询问。探索任务的判断标准是实际不能写入工作区,不能只凭界面上“自动”或“询问”的标签判断。 启动后第一句先让 Codex 报告环境:
这一步的价值在于把“它到底在哪工作”和“它准备怎么查”提前暴露出来。若工作目录不对,先退出并在正确目录启动;不要让后面的目录和调用链结论建立在错误根目录上。

AGENTS.md 的读取顺序

探索陌生项目时,规则文件本身就是第一批上下文。不要只打开仓库根目录的 AGENTS.md 就认为规则读完了。 按照参考资料中的 Codex 发现机制,通常按以下顺序理解:
  1. 先看 Codex 主目录中的全局规则。默认是 ~/.codex/,如果设置了 CODEX_HOME,则以该环境变量指向的目录为准。
  2. 在全局层,如果同时存在 AGENTS.override.md 和 AGENTS.md,优先取 AGENTS.override.md;这一层只取一个非空文件。
  3. 确定项目根后,从项目根目录向下走到当前工作目录。
  4. 每个目录依次查找 AGENTS.override.md、AGENTS.md,再查找配置中的 project_doc_fallback_filenames 备选文件名;每个目录最多取一个非空文件。
  5. 找到的项目级规则按“根目录到当前目录”的顺序合并。越靠近当前目录的规则越晚出现,冲突时通常以更具体的规则为准。
可以把它记成:
这里有两个容易误解的地方:
  • AGENTS.override.md 只替换同一目录的候选文件,不会清掉其他目录已经合并的规则。
  • AGENTS.md 是指导来源,不是目录索引。它可能规定测试命令、禁止访问的目录、生成文件策略和代码库特有约定;这些内容必须进入探索计划的约束。
让 Codex 显式报告规则来源:
如果结论和你的预期不一致,按顺序排查:当前目录是否正确、Git 根是否正确、CODEX_HOME 是否改变、是否存在更近的 override、规则文件是否为空、配置中的备选文件名是否拼写正确。改动配置后需要重启 Codex,不能在原会话中假定新规则已经生效。

第二步:从目录建立结构地图

目录探索的目的不是把每个文件都读一遍,而是建立“边界和职责”的假设,再用入口和调用链验证假设。

先看一级结构

先执行低成本命令:
若文件很多,先按目录统计或只看一级目录:
Windows 环境也可以使用 rg --files,不要把 .git、依赖目录、构建产物和覆盖率目录当成业务模块。 让 Codex 输出目录地图时,要求它区分证据和推断:

优先阅读的文件

不同项目的文件名会变化,但优先级通常稳定: 不要一开始读取所有锁文件、编译产物和大型数据文件。它们可能有用,但通常不能帮助你快速建立业务调用链。

目录不是架构结论

目录名只能产生候选假设。例如 services/ 可能是领域服务,也可能只是 HTTP 客户端;utils/ 可能承载关键权限逻辑;tests/ 可能只包含端到端测试。报告中应使用“看起来”“候选”“待通过符号引用确认”等措辞,直到你读到定义和调用点。 错误的目录结论:
更可靠的结论:

第三步:从目录找到真实入口

入口是“外部事件第一次进入业务代码的位置”。不同项目入口不同: 先问 Codex 找候选,不要直接让它“讲完整架构”:
再用搜索命令核对 Codex 的候选:
搜索词要根据项目语言调整。不要把一个大而模糊的正则表达式当作证据;每个候选都要回到文件中阅读注册语句和定义。 入口报告建议包含:

第四步:沿调用链追踪

目录告诉你“可能在哪里”,入口告诉你“从哪里开始”,调用链则回答“实际经过什么”。一次有效的调用链追踪至少要完成这五件事:
  1. 记录入口函数的定义和参数。
  2. 找出它直接调用的本地符号。
  3. 对每个关键符号继续追到实现,而不是停在导入语句。
  4. 标注条件分支、异常处理、外部调用和数据转换。
  5. 到达持久化、响应构造、消息发布或任务完成等终点。

先追一条主路径

不要同时追十条流程。先选择一个具体场景,例如“有效请求创建订单”,写清触发条件和预期终点:

用符号搜索补齐链路

Codex 的叙述需要被搜索证据约束。常用命令:
对 TypeScript、Python、Go 等项目,搜索导入和调用的习惯不同,但原则相同:定义、注册、调用三类证据要分开记录。

画出带证据的链路

探索输出不要只写一段散文。使用编号链路,读者可以从任一节点回到文件:
每一步都要能回答“下一跳为什么是它”。如果只能说“应该会调用”,就标为推断,不要升级为事实。

追踪分支和副作用

只追成功主路径会漏掉最重要的行为。至少追加三条分支问题:
特别注意以下容易断链的结构:
  • 依赖注入容器让构造函数里没有直接的实现名称。
  • 装饰器、注解或元数据在运行时注册路由。
  • 事件发布让调用关系从同步函数跳到消费者。
  • 接口、抽象类或函数类型让实际实现由配置决定。
  • 生成代码、宏或代码生成脚本隐藏了入口。
  • 前端请求经过 API 客户端、状态管理和中间件后才到组件。
遇到这些结构时,先搜索注册表、配置和工厂,再下结论。不要因为静态文本中没有直接调用就断言“没有调用”。

第五步:映射到测试

调用链完成后,马上问“哪些测试证明了这些节点”。测试映射不是只找同名文件,而是把生产路径的行为节点与测试类型对应起来。

先识别测试体系

读取测试配置和项目脚本:
让 Codex 先归类:

建立映射表

推荐用下表记录,而不是只写“测试比较完整”: “测试文件名看起来相关”不是覆盖证据。至少要看到调用目标、输入和断言;如果使用 fixture 或共享 helper,还要继续追 helper 最终做了什么。

反向从测试追生产代码

正向从入口到测试容易遗漏测试专用路径,因此再反向抽查:
这一步常能发现“单元测试全绿但真实请求失败”的原因:测试直接调用服务类,绕过了鉴权;mock repository 永远成功,掩盖了事务错误;测试断言返回对象,却没有检查 HTTP 状态和序列化格式。

Codex 探索提示词工具箱

下面的提示词都以只读为前提。使用时把项目事实、路径和业务名替换成实际内容。

目录地图提示词

入口定位提示词

调用链提示词

测试映射提示词

事实核验提示词

命令证据:让报告可以复查

高质量探索报告不是命令清单,而是“问题、命令、输出、结论”的对应关系。建议记录以下证据: 不要把完整终端日志未经整理地塞进报告。保留足以复查的关键输出,命令失败时保留退出码、错误文本和当时的工作目录。

有效和无效的命令证据

无效:
问题是没有命令、路径、匹配内容,也没有说明“负责”如何被确认。 有效:

什么时候继续探索,什么时候切计划

只读探索没有“读得越多越好”的原则。它的终点是关键事实足够支撑下一步决策。

继续只读探索的信号

  • 还不知道真正入口,只有目录名和猜测。
  • 同一个符号有多个实现,运行时选择方式未确认。
  • 调用链在依赖注入、事件总线或生成代码处断开。
  • 关键分支、权限检查、事务边界或外部副作用未定位。
  • 测试命令会写快照或启动未确认的外部服务。
  • 结论和 AGENTS.md、README、代码证据互相矛盾。
继续探索时缩小问题,不要再次要求“分析整个项目”:

可以切计划的信号

当下面几项都明确时,可以从只读探索切到计划:
  • 目标入口和关键调用链已经有路径、符号和调用证据。
  • 需求影响范围和明确非目标已经写清楚。
  • 相关测试命令、已有覆盖和缺口已经知道。
  • AGENTS.md 中的项目规则和禁止操作已经纳入约束。
  • 仍然存在的未知项不会改变方案,或已经显式列为风险。
此时不要直接让 Codex 改代码。先切换任务边界:
复杂任务可以显式使用计划模式或 $plan 技能,具体名称以本机支持为准。计划不是批准书:看完计划后仍需检查文件范围、是否把未知项伪装成事实,以及验证步骤是否真正能证明目标行为。确认计划后,再启动可写工作流。

错误示例与修正

错误一:一上来就让它修

错误提示:
问题:没有入口、现象、复现、约束或只读边界。Codex 可能从一个看似相关文件开始修改,最终只消除了表面错误。 修正:

错误二:只看目录就下架构结论

错误结论:
问题:目录名不是调用证据,真正逻辑可能在路由、中间件、领域对象或 SQL 查询中。 修正:读取入口处理器,搜索具体符号的定义、导入和调用,并用编号链路记录实际依赖。

错误三:把相似名称当调用关系

错误结论:
问题:相似名称可能来自未使用的旧实现、测试替身或不同包。 修正:确认导入来源、实例构造或容器注册,再确认实际调用表达式;动态绑定无法确认时标记未知。

错误四:把测试文件名当覆盖证明

错误结论:
问题:测试可能只覆盖格式化函数、使用 mock 绕过入口,或只断言不抛异常。 修正:读取测试用例、输入、调用目标和断言,标记直接、间接、未覆盖和无法确认。

错误五:为了探索而运行会写文件的命令

错误做法:
问题:这些命令可能更新快照、格式化源文件或生成代码,已经超出只读边界。 修正:先查看脚本定义和工具帮助,使用收集测试、干运行或只检查模式;无法确认时停下请求批准。运行后检查:

错误六:忽略更近的 AGENTS.override.md

现象:Codex 使用了和你看到的根规则不同的测试命令。 问题:当前子目录可能存在 AGENTS.override.md,或全局 CODEX_HOME 指向了另一套规则。 修正:按全局、项目根到当前目录逐级列出实际文件,确认同级 override 的优先关系,再重启会话验证。

真实项目演练:从目录到测试映射

下面以一个常见的真实项目形态演练:一个使用 TypeScript、Express、PostgreSQL 和 Jest 的订单 API。项目名和路径是演练中的脱敏示例,重点是方法;不要把示例路径当成你本地项目的事实。

场景和目标

目标是理解“创建订单”请求:
明确本轮不做:
  • 不修改 API 行为。
  • 不修复发现的缺陷。
  • 不新增测试。
  • 不启动真实支付服务,不访问生产数据库。
  • 不安装依赖、不更新快照、不提交。

1. 读取规则和项目基线

在项目根执行:
假设得到:
先记录 src/config/logger.ts 已经被修改。它不是本轮探索产生的结果,后续报告不要把它列入本轮变更。 读取 AGENTS.md 和 README.md 后得到项目规则:测试使用 pnpm test,类型检查使用 pnpm typecheck,禁止修改迁移历史,外部服务只能使用测试替身。这个规则会影响后续验证选择。

2. 看包配置和目录

读取 package.json 的 scripts 和依赖:
假设证据显示:
  • src/server.ts 创建 Express 应用并监听端口。
  • src/api/routes/order-routes.ts 注册订单路由。
  • src/application/ 存放用例服务。
  • src/infra/ 存放数据库和外部客户端。
  • tests/api/ 测试 HTTP 行为,tests/application/ 测试业务用例,tests/infra/ 测试数据库适配层。
此时只能说“目录呈现这种分层”,还不能说所有请求都严格遵循它。

3. 定位订单入口

执行:
假设得到:
入口已经由路由注册确认:POST /orders 先经过 auth,再调用 createOrderHandler。但还不能推断 auth 的拒绝行为,继续读取它的实现和测试。

4. 追踪成功主路径

搜索定义、导入和调用:
假设读取到以下链路:
继续检查异常和副作用:
假设发现:
  • 空商品由 Order.create 抛出 EmptyOrderError。
  • 库存不足由 inventoryClient.reserve 转换为 OutOfStockError。
  • 请求 ID 由中间件传入,但 DuplicateRequestError 的处理在 order-service.ts,需要核对是否在写库前执行。
  • 订单保存成功后 order-events.ts 发布 order.created,但事件发布发生在数据库事务提交后,消费者属于另一条异步链路。
报告里应把同步主链和异步副链分开,不要把事件消费者伪装成 HTTP 请求的直接下一跳。

5. 映射现有测试

先读取测试命令:
形成映射: 再反向检查 tests/api/order-route.test.ts 是否绕过了真实依赖。假设它通过 createTestApp() 注入内存 repository 和库存 mock,那么应写出限制:它能证明路由、中间件和响应映射,但不能证明生产数据库事务或真实库存客户端协议。

6. 输出本次探索结论

合格的演练报告可以收束为:
最后再次证明探索没有写入工作区:
预期只有开始前已经存在的 src/config/logger.ts 修改,没有本轮新增文件或 diff。

探索输出模板

将以下模板贴给 Codex 或用于自己的笔记。它强制报告从目录到测试的证据链:
如果 Codex 的输出没有路径、符号、命令或未知项,要求它按模板重写。探索报告的可用性取决于证据密度,不取决于篇幅。

验收清单

完成陌生代码库探索后,逐项核对:
  • 当前工作目录和 Git 根目录已由命令确认。
  • 当前分支和探索前已有修改已记录。
  • 全局到当前目录的 AGENTS.md 读取顺序已确认。
  • 规则中的测试命令、禁止操作和目录约束已进入报告。
  • 顶层目录只作为候选假设,没有被直接当作架构结论。
  • 目标功能至少找到一个真实入口,并有注册位置证据。
  • 调用链包含定义、调用、参数变化和关键终点。
  • 鉴权、校验、事务、异常和外部副作用已单独检查。
  • 测试映射包含用例和断言证据,而不只是文件名。
  • 单元、集成、端到端或契约测试的边界已区分。
  • 动态分发、事件链和生成代码造成的不确定点已标出。
  • 所有无法确认的内容写入未知项,没有为了完整而猜测。
  • git status 和 git diff --check 证明只读探索没有产生改动。

小结

陌生代码库探索可以压缩成一条可复查的路线:
Codex 最适合做的是快速收集和整理证据;你的职责是确认边界、辨别事实与推断,并决定什么时候从“了解系统”进入“改变系统”。只读探索做得好,后续修复、开发、重构和补测试才有明确范围,计划也不会建立在一个漂亮但错误的目录摘要上。