我如何让 Codex 自己维护 AGENTS.md 和 Skill
本文来自我的实际项目实践。为了避免泄露项目细节,模块路径、接口、编号和内部依赖均已脱敏,但问题、判断和处理过程都是真实发生过的。
有一次,Codex 为一个“扫描列表并取最大值”的私有函数单独写了测试。这个函数只有几行,测试几乎是把实现重新抄了一遍。为了测试它,代码边界反而变得更别扭。
我没有只让 Codex 删除这个测试,而是继续告诉它:
删除这个简单 helper 的独立测试。 测试应该保护业务行为,而不是按函数数量配置。 检查现有 Skill,把这次纠偏提炼成以后都要遵守的测试边界。Codex 最后修改了test-driven-development:序列化兼容、非法状态拦截、热更新保留旧快照,这类行为值得测试;简单查找、字段复制、最大值扫描,不值得为了“有测试”而单独测试。
这件事让我确定了一种用法:AGENTS.md和 Skill 都不需要手写。规则应该从真实任务和真实纠偏中长出来,再让 AI 帮我整理、归位和持久化。
我的规则体系到底怎么分工
我现在使用的不是一份越来越长的提示词,而是下面这套分层:
仓库 AGENTS.MD:团队和仓库硬规则,所有 agent 都必须遵守 ~/.codex/AGENTS.MD:我的本地路由和 Codex 使用习惯 ├── 这次任务用直接实现、Superpowers,还是 Speckit └── 进入项目后需要加载哪些项目 Skills 项目 Skills ├── code-standards:所有代码修改的基础 Skill ├── develop-new-business:新业务端到端编排 ├── 专项 Skills:配表、TCP、alert、条件状态、流水、测试等 └── test-driven-development:判断回归测试边界这两层AGENTS很容易写混。
仓库AGENTS.MD是团队共享的硬规则,例如目录依赖方向、持久化和通知顺序、外部编号不能猜、用户已有改动不能被覆盖。这些规则不依赖我使用什么 AI 工具,换一个 agent 也应该遵守。
~/.codex/AGENTS.MD是我的本地控制台。它记录我怎样使用 Codex:中文技术任务怎样回答,什么时候先做设计,什么时候先查根因,以及哪些任务应该加载哪些 Skill。我的“每次修改代码都先加载code-standards”就写在这一层,因为 Skill 必须在被选择之前完成路由,不能靠 Skill 正文要求自己被加载。
Skill 不是平铺清单,而是一条职责链
最初我的 Skills 也出现过重复:新业务 Skill 既写项目分层,又复制 TCP、配置、错误码和测试规则,慢慢变成了第二本项目手册。后来我让 Codex 遍历所有 Skills,把重复内容归回唯一负责人。
现在它们的分工是这样的:
| Skill | 我让它负责什么 | 明确不负责什么 |
|---|---|---|
code-standards | 全仓地图、分层、通用编码风格、日志错误、副作用顺序和完成前检查 | 不展开某个领域的全部操作步骤 |
develop-new-business | 判断新业务影响哪些层、需要加载哪些专项 Skill、怎样组织端到端交付 | 不沉淀具体编码细则,也不用于单点修复 |
read-main-server-code | 从入口追到状态、存储和回包,先建立代码证据 | 不直接实现功能 |
config-table-integration | 配置生成结果、手写包装层、索引、校验和热更新发布 | 不修改生成代码,不承载业务编排 |
tcp-proto-integration | 协议契约、任务生命周期、注册链和薄入口 | 不在 handler 中堆业务,不猜外部包号 |
alert-error-governance | 用户可见错误语义、错误码、消息映射和调用一致性 | 不替代通用日志规则 |
condition-unlock-state-development | 条件订阅、默认态与持久化态合并、可靠重试和修复闭环 | 不负责协议展示和属性系统 |
flow-record-development | 流水结构、外部类型、producer 字段和发送时机一起核对 | 不猜类型编号,不给初始化路径乱写流水 |
test-driven-development | 判断什么行为值得留下回归测试、测试放在哪个稳定边界 | 不负责测试环境搭建 |
testing-main-server | TestMain、测试环境、聚焦测试命令和失败诊断 | 不决定一个测试有没有业务价值 |
这里最有意思的是测试分工。
- Superpowers TDD 解决“怎样做 red-green-refactor”;
test-driven-development解决“这个项目里什么值得测”;testing-main-server解决“测试怎样在真实项目环境里跑起来”。
如果把三者合成一个 Skill,它要同时懂方法论、业务价值和环境初始化,很快又会变成一份没人愿意维护的长文档。
一次新业务是怎样被分发的
以我实际做过的一类“配置条件满足后解锁用户状态”的需求为例。它表面上只是增加一个功能,实际会碰到配置、状态持久化、条件回调、客户端入口、错误返回、流水和测试。
我的分发过程不是“把所有 Skill 都加载一遍”,也不是限制最多加载两个,而是加载影响面需要的最小集合:
需求边界还不明确 -> Superpowers brainstorming 先把状态、入口和副作用谈清楚 开始落地 -> code-standards 提供全仓地图和编码基线 -> develop-new-business 识别影响面并安排交付顺序 -> read-main-server-code 追现有调用链 -> 配表 Skill 处理配置和热更新 -> 条件状态 Skill 处理默认态、持久化和可靠回调 -> TCP Skill 处理协议入口与注册 -> alert Skill 处理用户可见错误 -> 流水 Skill 处理真实状态变化后的记录 -> 项目 TDD Skill 选择回归边界 -> 测试执行 Skill 负责把聚焦测试跑起来develop-new-business在这里像调度员。它知道应该找谁,却不替任何专项 Skill 干活。比如它只判断“这个需求涉及配表”,真正的热更新规则仍由配表 Skill 维护。
如果需求明确要求产出spec.md、plan.md、tasks.md并按文件追踪交付,我会改走 Speckit。Superpowers 更适合日常设计、debug、TDD 和计划执行;Speckit 更适合正式的规格化需求流程。两条完整流程一般不同时跑,否则很容易出现两份 plan 和两个任务真相。
无论从 Superpowers 还是 Speckit 进入编码阶段,项目基础 Skill 和命中的专项 Skills 仍然要加载。工作流 Skill 决定“怎么推进任务”,项目 Skill 决定“在这个仓库里怎么做才对”。
我的 Skills 是怎样从任务里长出来的
案例一:评审后把日志纠偏写回基础 Skill
有次 Codex 遇到业务状态异常,先临时构造一个error,目的只是把它传给日志函数。代码能跑,但这个错误不是下层真实返回的,会混淆错误来源。
我让它改成:当前分支自己判断出的异常直接记录nil错误并补充运行时上下文;只有下层真实返回的err才原样记录和返回。修完当前代码后,我又让它把规则写进code-standards。
为什么不是新建一个 Skill?因为这条规则适用于所有代码修改,应该进入每次编码都会加载的基础 Skill。以后再写业务代码,Codex 在动手前就能看到它。
案例二:任务完成后提炼出配表恢复流程
有次源配置明明存在,代码却找不到对应的生成包。最容易做出的错误判断是“生成代码还没做”,甚至在本地手写一个替代结构。
继续检索依赖版本后发现,真正原因是生成依赖没有更新。刷新生成依赖并重新查询后,包就出现了。任务完成后,我让 Codex 把这条经验写进配表 Skill:源数据存在但生成包缺失时,先检查并更新生成依赖,再重新检索,不要先造替代实现。
这个经验只属于配表领域,没必要让每次普通代码修改都加载。
案例三:把新业务 Skill 从“百科全书”改回编排器
develop-new-business曾经重复维护过项目分层、TCP、配置、alert 和测试规则。修改一条规范时,需要在多个 Skill 里同步,很快就开始漂移。
我让 Codex 比对所有 Skill 后,把它改成薄编排器:只保留影响面清单、companion Skill 路由和交付检查。具体细则回到基础 Skill 或专项 Skill。另一个与 Superpowers brainstorming 重复的设计 Skill 也被删除了。
这次经验让我意识到,Skill 的质量不取决于数量。发现两个 Skill 说同一件事时,合并或删除通常比继续补文档更重要。
案例四:做完一次流水任务,再创建流水 Skill
一开始我没有专门的流水 Skill。一次完整任务做下来,发现每次都要重复核对:结构字段、存储元信息、外部类型申请、生成常量回填、真实 producer、发送时机和邮件材料。
于是我让 Codex 复盘刚才的全过程,删除业务名称和一次性参数,只保留可复用的搜索顺序、停止条件和验证方式,最后形成flow-record-development。
这就是我创建 Skill 最常用的方式:先把任务做对,再把做对的路径提炼出来。
我怎样让 AI 修改规则
我很少打开SKILL.md从第一行开始手写,通常直接继续和 Codex 对话。
任务完成后,我会这样问:
复盘刚才的任务,找出以后还会重复使用、仅靠普通搜索不容易稳定得到的经验。 先检查现有 AGENTS 和 Skills,判断应该更新已有文件还是创建新 Skill。 删除本次业务专属信息,保留触发条件、执行顺序、停止条件和验证方式。发现代码不符合规范时,我会这样问:
先修正当前代码,再判断这个问题是全仓硬规则、基础编码经验,还是专项领域规则。 把规范持久化到唯一负责人,检查是否与现有规则重复或冲突。隔一段时间,我还会让 Codex 检查规则体系本身:Skill 是否存在却没有路由入口,正文和引用是否使用了过期路径,两个 Skill 是否职责重叠。实际检查中,我确实发现过“专项 Skill 已经存在,但上层路由没有显式列出”以及“旧 Skill 仍引用过期代码位置”的情况。
所以,让 AI 写规则不等于不检查规则。AI 负责搜索、归纳和修改,人仍要判断这条经验是否长期成立、作用域是否正确、能否被触发、有没有验证方式。
AI 时代真正重要的三种能力
回头看,我并没有因为使用 Codex 而背下更多命令,反而把精力放到了三件事上。
第一是提问。不要只说“帮我写代码”,而要说明目标、边界、哪些内容不能猜、什么结果算完成。任务结束后还要继续问:“这次有什么值得成为下次默认行为?”
第二是检索。让 AI 先读当前AGENTS.md、Skills、相似代码、生成产物和调用链,用项目证据决定怎么改。很多错误并不是不会写代码,而是没有找到真正的负责人和现有模式。
第三是检查。检查 AI 写的代码,也检查 AI 写的规则:是否放对层级、是否重复、是否能命中、是否已经过期、是否有测试或命令可以验证。
AGENTS.md和 Skill 只是载体。真正有价值的是把一次提问、一次检索、一次纠偏,变成下一次任务开始前就会生效的默认经验。做到这一点,Codex 才不是一个每次都要从头解释的代码生成器,而是一个会随着项目实践逐步变得更合适的工程协作者。