Chengshu@skadai · 2026.10.20
RSS
1,731 字 · 545 词 · 约 7 分钟

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.

流程只有四步:

  1. 先调 writing-for-agents 拿写作风格。这一步很特别——它借的是另一个技能的文体规范,因为它的产物是写给 agent 读的指令,文体本身就是内容的一部分。
  2. 读这次会话的一手材料: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:它不是问你「这次哪里不顺」,它是去读日志。
  3. 按七个分类找改进候选,每个分类后面都附一条 _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 日志、给第三方服务只读权限)?
  4. 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.md for 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.md for 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.

可迁移结论

  1. 把复盘的宾语从「代码」换成「环境」。 「这里是什么结构让它发生」比「这里做错了」更能产出可执行的结果。
  2. 每条建议都配一个「何时提」的触发条件。 _Use when_ ... 让清单跟着症状走,而不是覆盖所有分类。
  3. 先分类,再决定落点。 机械违规给确定性检查(full stop),判断题才写进 CODING_STANDARDS.md——默认造检查,不是写规则。
  4. 把规则放在有上下文余量的阶段。 实现 agent 忙着探索和调试,规范归 reviewer;AGENTS.md 只放导航指针。
  5. 先把仓库已有的检查读一遍。 一个没接上或悄悄坏掉的检查,比一条新规则更值得修。
  6. 把「没有护栏」记成发现,而不是默认。 没坏消息不等于没事。
  7. 只提议,不自动挂上。 什么值得一个永久检查是人的判断;顺带接受「顺利的会话没什么可教的」——不是每次都要跑。
  8. 自己修剪检查。 retro 只看一次会话,管不了它上个月提的那些规则;一条频繁误报的规则就是删除信号。

retro 和 improve-codebase-architecture 是这套技能里对称的两端:一个在代码里找加深机会,一个在环境里找漏。它们的共同点是都不动手——一个产出 HTML 报告,一个产出排序过的候选清单,施工都留给别的回合。

讨论

用 GitHub 账号留言;评论保存在公开仓库chengshu-blog-discussions的 Discussions 里。也可通过 RSS 订阅后续文章。