retro 精读:它改的不是代码,是 agent 的环境
retro 是一次取证式的复盘:它读会话的一手日志,按七个分类(导航、自动检查、编码规范、AGENTS.md、工具经济性、no-ops、信息获取)找改进候选,按严重程度排好交给你,自己一行代码都不改。它的核心规则只有一条——机械违规交给确定性检查,判断题才写进 CODING_STANDARDS.md,且默认「先造检查,再写规则」;并且它把「一个连护栏都没有的仓库」本身记成一条发现。本文走一遍它的四步流程,讲清它为什么把规范的责任放在 reviewer 而不是 implementer、为什么 AGENTS.md 要极简、以及它自己承认的那个最弱的地方。
本篇属于系列 读懂最优秀的开发技能是怎么写的(Matt Pocock skills 逐技能精读) · 第 23 篇
(本文读的是 mattpocock/skills 快照 5beb35b,2026-10-19。引用原文都能按文中路径回仓库核对。这是「逐个技能精读」系列的第二十三篇,聚焦 retro 一个技能。)
它怎么工作:读一次会话的一手记录,按七个分类找环境里的漏
skills/engineering/retro/SKILL.md 只有 44 行,user-invoked(disable-model-invocation: true),开头第一句就把对象定死了:
The user has asked for a retrospective. You are suggesting improvements to the coding agent’s environment to improve future runs.
环境,不是代码。文档把这句话展开了一段:拿这次会话里 agent 发出去的那个 bug、它花了二十次工具调用才找到的那个文件、reviewer 漏掉的那条规则来说——retro 一个都不直接修,它问的是「仓库里是什么东西让这些得以发生」,然后提出能防止下次再发生的检查、指针或规范。而且它只提议:It also only proposes. Nothing changes until you pick a candidate.
流程只有四步:
- 先调
writing-for-agents拿写作风格。这一步很特别——它借的是另一个技能的文体规范,因为它的产物是写给 agent 读的指令,文体本身就是内容的一部分。 - 读这次会话的一手材料:
Read the primary sources for the session the user specifies. This may mean searching through session logs on this machine. If the user doesn't specify a session, default to the current one.注意 primary sources 和 session logs:它不是问你「这次哪里不顺」,它是去读日志。 - 按七个分类找改进候选,每个分类后面都附一条
_Use when_触发条件:- Navigation:找文件的路径顺不顺?文件之间有没有隐藏依赖?——
_Use when_ the session took a long time to find a piece of information. - Automated checks:有没有本来能接住这个错误的检查?——先读仓库自己的 check 命令;
A repo with no **guardrail** ... is itself a finding。 - Coding standards:reviewer 该不该多一条或去掉一条规则?
- Global AGENTS.md:有没有该搬去规范或检查的 steering?——
_Use when_ the AGENTS.md file is particularly large。 - Tool economy:有没有昂贵到可以省的调用?
- No-ops:steering 文件里有没有不改变 agent 行为的句子?
- Information access:有没有本该开放的访问(tee dev server 日志、给第三方服务只读权限)?
- Navigation:找文件的路径顺不顺?文件之间有没有隐藏依赖?——
Present these candidates to the user, in order of severity.
七个分类里最硬的是第三条的两条规则。它要求先把违规分类,再决定落点:
Classify the violation first: a mechanical one (a fixed syntactic pattern, a banned API, an import shape, a file-location rule) gets a deterministic check, full stop … Default to building the check over writing the rule. Reserve
CODING_STANDARDS.mdfor genuine judgement calls
也就是:机械违规 → 确定性检查;判断题 → CODING_STANDARDS.md,而且默认是「造检查」而不是「写规则」。
参考区还有两小节。一是 Implementation vs Review:实现 agent 的上下文压力最大(要探索、写码、调试失败),评审 agent 压力最小(只拿到一份 diff,不需要探索,往往也不用写码或调试),所以 the review agent should be responsible for imposing coding standards, not the implementation agent。二是 Files:CLAUDE.md/AGENTS.md 会被推进任何在该仓库工作的 agent 的上下文窗口,所以 used incredibly sparingly, usually only for **navigation pointers**;CODING_STANDARDS.md 在评审时读、不在实现时读,超过 1000 行就加指针指向 docs;写新文档前先找已有文档。
它和「一般技能」的差别:一份取证报告,而不是一次感想
一、retro 的对象是环境,不是代码。 一般的会话复盘会总结「这次做了什么、哪里做得不好」;这里的问题被重新定义成「仓库里的哪一处结构、哪一条规则、哪一件工具,让这次变得不顺」。这个改写让结论可以直接变成文件改动。
二、它是阅读器,不是访谈者。 它读 session 日志,默认当前会话;这跟 triage 读 issue 全文、code-review 读 diff 是一路数:技能消费的是一手记录,不是人的回忆。
三、每个分类都带触发条件。 _Use when_ ... 这一句是它的自适应机制——没有对应症状就不提这一类,报告因此不会退化成一份便宜的通用建议清单。
四、分类规则把措辞压力从人身上移走。 「机械 vs 判断」是一次分类,不是一次取舍;机械的必须变成确定性检查(full stop),判断题才配写散文。这消掉了最常见的坏结果——为一条 lint 能管的规则写一段没人会读的规范。
五、它先读仓库已有的检查。 原文说得很好:一个已经存在但没接上、或悄悄坏掉的检查,本身就是发现——a check that already exists but sits unwired or silently broken is the finding, not a reinvention。
六、它敢说「没有护栏本身就是发现」。 如果 repo 连 pre-commit 都没有、CI 也不跑 lint/typecheck/test,那 an un-linted repo is a standing missed opportunity, not a neutral default. 这句话把「没坏消息」从默认状态改成了一条发现。
它有意识摒弃了什么
一、摒弃了「直接修」。 它不写那条 lint 规则、不装那个 hook,只提议,等你挑。文档给了理由:有用户被「自动挂钩挡住了好的改动」烫过;「什么值得一个永久的检查」是个判断,所以技能保持 human-in-the-loop,并保持 user-invoked。
二、摒弃了在实现阶段讲规范。 规则归 reviewer。理由比技能本身还直白:实现 agent 上下文压力最大,而 AGENTS.md 又会被推进每个 session 的上下文窗口,无论相不相关。
三、摒弃了「写一段规则就算完」。 Default to building the check over writing the rule. 检查能失败,规范里的一句话不能。
四、摒弃了凭空提议。 先读 package.json、构建工具的 lint/check 脚本、CI workflow,再决定提什么。
五、摒弃了「steering 越多越安全」。 no-ops 是一个独立分类(look for instructions in steering files that don't modify the agent's behavior),AGENTS.md 的要求是极简、只放导航指针。
六、摒弃了「没有检查是中性默认」。 没有护栏等于一条发现。
七、摒弃了「每次会话后都跑一遍」。 文档里说:一次顺利的会话没什么可教的——每次跑一遍,产出的多半是没人需要的规则。
八、摒弃了给自己免责的话术。 文档直接承认了它最弱的一处:它只看一次会话,管不了它上个月提的那些 hook、CI 和 lint 规则;一条规则现在是不是误报太多、它背后的 bug 是不是早没了,它答不了——你得自己修剪检查。一条在好代码上频繁误报的规则,就是该删的信号。
原文证据
对象与产出:
The user has asked for a retrospective. You are suggesting improvements to the coding agent’s environment to improve future runs.
Present these candidates to the user, in order of severity.
分类规则与落点:
Classify the violation first: a mechanical one (a fixed syntactic pattern, a banned API, an import shape, a file-location rule) gets a deterministic check, full stop: a custom rule in the repo’s own linter, a new pre-commit hook, or a new CI job, whichever the repo’s language and existing guardrail make cheapest. Default to building the check over writing the rule. Reserve
CODING_STANDARDS.mdfor genuine judgement calls … Use when the reviewer agent failed to catch a mistake.
护栏:
A repo with no guardrail (no pre-commit hook and no CI job running its lint/typecheck/test command) is itself a finding: an un-linted repo is a standing missed opportunity, not a neutral default.
责任划分:
This means that the review agent should be responsible for imposing coding standards, not the implementation agent.
可迁移结论
- 把复盘的宾语从「代码」换成「环境」。 「这里是什么结构让它发生」比「这里做错了」更能产出可执行的结果。
- 每条建议都配一个「何时提」的触发条件。
_Use when_ ...让清单跟着症状走,而不是覆盖所有分类。 - 先分类,再决定落点。 机械违规给确定性检查(
full stop),判断题才写进CODING_STANDARDS.md——默认造检查,不是写规则。 - 把规则放在有上下文余量的阶段。 实现 agent 忙着探索和调试,规范归 reviewer;
AGENTS.md只放导航指针。 - 先把仓库已有的检查读一遍。 一个没接上或悄悄坏掉的检查,比一条新规则更值得修。
- 把「没有护栏」记成发现,而不是默认。 没坏消息不等于没事。
- 只提议,不自动挂上。 什么值得一个永久检查是人的判断;顺带接受「顺利的会话没什么可教的」——不是每次都要跑。
- 自己修剪检查。 retro 只看一次会话,管不了它上个月提的那些规则;一条频繁误报的规则就是删除信号。
retro 和 improve-codebase-architecture 是这套技能里对称的两端:一个在代码里找加深机会,一个在环境里找漏。它们的共同点是都不动手——一个产出 HTML 报告,一个产出排序过的候选清单,施工都留给别的回合。
讨论
用 GitHub 账号留言;评论保存在公开仓库chengshu-blog-discussions的 Discussions 里。也可通过 RSS 订阅后续文章。