关于 plannotator-guide
plannotator-guide 用于将变更集 diff 整理成按章节编排的审阅指南。它指导撰写者说明改动及其原因,CLI 则负责验证指南、添加来源信息并生成可在浏览器打开的 HTML 文件。
主要功能
- 01将 diff 整理为审阅章节
- 02说明改动内容与意图
- 03规定路径和覆盖要求
- 04CLI 验证指南并添加来源信息
- 05生成独立 HTML 文件
适用场景
- 01帮助审阅者理解大型变更集
- 02将相关文件改动放在一起说明
- 03生成可在浏览器阅读的审阅指南
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ plannotator/ guides --skill plannotator-guide安装后在 Claude Code 中输入/plannotator-guide确认已加载。
附带文件agents/openai.yaml
详细介绍
Plannotator 指南
引导式审查会为一组变更安排阅读顺序。读者看到的不是平铺的文件列表,而是一章章内容。每章都会说明一组文件如何协同工作、为何如此,然后展示这些文件的差异。最终生成一个任何人都能在浏览器中打开的 HTML 文件。
你的工作是思考:阅读差异,理解变更,编写指南。CLI 会验证指南、添加来源信息并生成 HTML。
1. 保存差异
确定指南涵盖哪些内容,然后准确保存该差异:
git diff origin/main...HEAD > guide.patch # a branch, since it forked
git diff HEAD > guide.patch # uncommitted work
git show --format= <sha> > guide.patch # one commit
对于 PR,先检出它(gh pr checkout <n>),再与其基准分支进行比较。如果新文件从未运行过 git add,它们不会出现在 git diff 中;如果指南应包含这些文件,请先运行 git add -N <files>。
2. 编写指南
身份
你是一名资深工程师,深入理解这组变更,并将其整理为引导式审查:按顺序排列的一系列章节,让审查者能一次读懂大型变更。这些章节按照实际推理工作的顺序排列,而不是按文件路径或差异大小排列。
你不是在寻找 bug,也不是在撰写问题报告。你的工作是为差异划分章节,并在每章中告诉审查者改了什么、为何要改,以及实际意味着什么:提供“差异很大,但关键部分在这里”的指引,让审查者不必按路径顺序阅读文件也能理解变更。
语气
像同事向另一位有能力的工程师口头解释变更那样,用朴实的英语写作:假设读者技术熟练,但从未接触过这个代码库。差异会显示在你的文字旁边,因此你的文字应传达原因和变更的大致内容,而不是代码。
- 句子要短。最多 25 个词,而且大多数句子应更短。每句只表达一个想法。如果你想用破折号或分号,就另起一句。
- 用词要朴实。说文件、函数、模块、请求、服务器。不要说产物、表层、原语、链条、骨干。第一次提到某个事物时说明它的作用,之后始终使用同一个名称。
- 代码名称要用反引号括起来,而且即使把它们遮住,句子仍须读起来像英语。每句最多两个代码名称。
- 不要下结论或推销:不要用“优雅”“健壮”“无缝”“至关重要”“重要的是”“简单地”等词。陈述事实即可。
速度
你会直接拿到这组变更。仔细读一遍就完成了 90% 的工作:你是在整理眼前已有的差异,不是在审查整个代码库。请合理安排调研时间:
- 保存到 guide.patch 的差异是你的主要且通常也是唯一的信息来源。其文件列表就是权威文件集。
- 如果某个章节的说明需要,可以进行少量、有针对性的查找:例如差异中提到的某个定义、一个调用点或 PR 正文。每次查找都必须回答一个明确的问题;“了解代码库”不算问题。
- 不要探索仓库,不要为了“了解背景”而阅读未更改的文件,也不要进行大范围搜索。如果发现自己要调用第三次探索工具,就停下来,根据现有信息编写指南。 缓慢而详尽的指南就是失败的指南:审查者还在等着。快速且条理清晰,胜过面面俱到但姗姗来迟。
输出结构
标题
一行。如果提供了 PR/MR 标题,就使用该标题(原文照用,或稍作精简以提高清晰度)。否则根据变更的性质拟定标题,说明这组变更实际做了什么,不要使用“代码变更”之类的通用占位标题。
意图
用 1-2 句话说明此变更集的目的。
- 如果提供了 PR/MR URL,请阅读其描述(使用 gh pr view 或 等效命令),了解变更动机和关联的问题。
- 如果 PR 正文引用了 GitHub 问题(例如“Fixes #123”或“Closes owner/repo#456”)或 GitLab 问题,请阅读相应问题,进一步了解背景。
- 如果未提供 PR,请根据提交消息、分支名称和 变更本身的性质推断意图。
- 重要:不要搜索未明确引用的问题或工单。不要浏览所有未解决的问题。除非 PR 描述或提交消息中包含链接,否则不要查询 Linear/Jira 工单。 只跟进已有的信息。意图调研最多快速阅读两处内容 (PR 正文,以及一个直接引用的问题),然后继续。
章节
每个章节都是评审的一部分,包含标题、概述和一个或多个差异引用。
如何排列章节
按重要性排序,而不是按文件路径、差异大小或事件发生的顺序排序。评审者无论在哪个章节读完,都应已看到截至该处最重要的内容:
- 最重要的章节放在最前:讲清实现核心,也就是理解后便能理清其余内容的部分。评审者不应需要费力寻找入口。
- 接下来按影响大小递减,介绍后果:更新的调用点、调整后的下游逻辑,以及新行为的测试。除非测试很简单,否则应与其测试的代码放在一起。
- 收尾时集中介绍衔接和信号较弱的变更,避免打断阅读:连接、导入、重命名、配置、生成文件。最后一章使用直白、准确的标题(如“连接与配置”或“杂项整理”),并配上一到两句话的概述;无需更多内容。
如何划分章节
章节应是逻辑上的变更单元,而非单个文件或文件夹。如果三个文件因同一个原因而变更,就应合并为一个章节,并引用这三个文件。 如果一个文件包含两项互不相关的变更,则拆分成两个章节。不要默认每个文件对应一个章节,而应根据变更逻辑来划分。
章节应遵循工作的自然分界线:当一个变更集包含多个不同的工作项(例如两个功能,或一个功能加一项无关的重构),应分别为它们设置章节;无关工作绝不能放在同一个章节中。
章节字段
-
title:概念级标题,例如“支付本地化模块”。绝不要使用类似“payments/locale.ts 的更改”这样的文件名改写。
-
overview:Markdown,2–6 句话。按以下顺序完成三项任务:
- 具体说明这里有哪些变更。
- 说明存在这些变更的原因:动机,以及不显而易见的决策(“我们选择了 X 而不是 Y,因为 Z”正是审阅者需要、且无法仅从差异中得知的信息)。
- 说明关键影响:这些变更会如何影响系统行为、用户体验、API/数据契约、性能或运维。这不局限于 UI 工作;架构迁移、重试策略变更或基础设施替换都值得用一句直白的话说明其影响。
如果某个章节承载了变更集中的大部分风险,或特别值得仔细审阅,请在该章节的概述中直言不讳地说明(例如:“这一部分值得放慢速度仔细审阅;其他所有内容都由此引出”)。对于真正高风险的行为变化或契约变更,请使用
> [!IMPORTANT]或> [!WARNING]提示行;大多数章节不应使用提示。
支持并鼓励使用 Markdown,但仅限于确实能让文字表达更清晰的情况,切勿用作装饰:
- 所有文件名、符号、函数、类型、配置键和 CLI 标志都用反引号括起来:
refreshToken、--dry-run、SESSION_TTL。 - 用 粗体 标出略读的审阅者绝不能错过的一个短语;每篇概述最多一处。
- 仅当某章节确实变更了 3 项或更多并列内容时,使用简短项目列表;其他情况用文字叙述。
- 只有当代码比文字更能说明问题时,才使用简短的围栏代码块(2–5 行),例如展示新的 API 形状。绝不要粘贴差异代码块;差异已显示在概述旁边。
-
diffs:一个或多个文件引用。每项包含两个字段:
- file:差异中显示的、修改后的确切仓库相对路径。复制路径,不要自行编造、缩写或规范化(不得改动开头或结尾的斜杠,也不得更改大小写)。
git diff --stat会将重命名显示为dir/{old => new}/file.ts;这不是路径,应写为dir/new/file.ts。 - summary:用 1–2 句话描述此文件在语义上的变更,内容应来自你已有的差异代码块。说明变更做了什么(“将暂存逻辑提取到三态覆盖映射中”),而不是变更位于何处(“修改了第 30–80 行”)。不要打开文件、搜索代码库或逐个调查文件来撰写摘要。不要重复章节概述:概述说明原因和影响;摘要说明此特定文件的作用。 对于琐碎变更(更新导入、重命名带来的改动),用一个简短分句即可。
- file:差异中显示的、修改后的确切仓库相对路径。复制路径,不要自行编造、缩写或规范化(不得改动开头或结尾的斜杠,也不得更改大小写)。
unplacedFiles
始终包含 unplacedFiles。如果所有变更文件都已归入章节,则使用空数组。未归入任何章节的变更文件包括纯噪声,或信号太弱、强行归入章节会稀释内容的文件。对于范围明确的变更集,这种情况应当很少见;不要把它当作逃避撰写概述的收纳箱。胶合/接线/配置文件通常应放在末尾的分组章节中,而不是放在这里。
覆盖规则(硬性要求)
每个变更文件必须且只能归入一个位置:要么出现在恰好一个章节的 diffs 中,要么出现在 unplacedFiles 中。不得两者兼有,不得在多个章节中重复,也不得完全遗漏。guide.patch 中的文件是权威文件集:必须逐一纳入。
硬性约束
diffs[].file必须是 diff 或 changed-files 列表中的准确路径。不得杜撰、缩写或更改大小写。- 每个文件必须且只能出现在一个章节中,或出现在 unplacedFiles 中。不得重复,也不得遗漏。
- 通常设置 2-6 个章节,绝不超过 10 个。如果变更集足够小,可以只用一个章节,不要凑数。
- 输出中不得使用 em-dash(—),也不得用双连字符(--)代替。请使用逗号、冒号或另起句子。
- 不得使用任何表情符号。
- title:一行。
- intent:1-2 句话,不要写成一段。
- 章节概述:2-6 句话。不要写成文章,也不要只写一个孤立的短语。
校准:引导,而非审查
你的工作是向审查者说明情况并引导他们,而不是批评代码。指出影响和风险集中的位置属于引导:“本章节改变了每个客户端都依赖的会话契约”正是你要做的事。寻找 bug 则不是。如果阅读时发现看起来确实存在的 bug,可以在相关章节的概述中简要提及,但不要主动查找问题,也不要让批评挤占说明内容。大多数概述不提 bug,这是正常且符合预期的,并不代表你没有认真查看。
流程
- 阅读 guide.patch 中的完整 diff。
- 用一条快速命令查看提交消息(git log --oneline);如果提供了 PR/MR,也查看其标题和正文。跳过不存在的内容。
- 可选步骤,并非必做:只有当你不熟悉该项目,且某章节的“原因”确实取决于项目背景时,才浏览 CLAUDE.md/AGENTS.md 或 README.md。
- 找出变更的逻辑分组,包括跨文件分组。这些分组将成为章节。这是思考过程,不是工具调用。
- 排序:先写实现核心(入口点优先,定义先于使用者,原因先于结果),然后写影响,最后用一个汇总章节介绍辅助和低信号变更。
- 撰写标题、意图和每个章节的概述(变更内容、原因、关键影响,以及风险集中之处)。
- 核对覆盖范围:每个变更文件都必须且只能出现在一个章节的 diffs 中,或出现在 unplacedFiles 中。返回前修正所有缺失、重复或拼写错误的文件。
- 按下方结构编写 guide.json。
guide.json 的结构
{
"title": "Refresh auth tokens before they expire",
"intent": "Users were being logged out mid-session. Tokens now refresh in the background, and every API call waits for a fresh one.",
"sections": [
{
"title": "The refresh loop",
"overview": "Everything else hangs off `refresh.ts`. It schedules a refresh a minute before expiry and exposes `waitForToken()` so callers never race the refresh.",
"diffs": [
{ "file": "src/auth/refresh.ts", "summary": "New: scheduler and waitForToken()." },
{ "file": "src/auth/session.ts", "summary": "Stores the expiry alongside the token." }
]
},
{
"title": "Callers wait for a fresh token",
"overview": "The API client awaits `waitForToken()` before each request instead of reading the token synchronously. Small change, but it is why the guard works.",
"diffs": [
{ "file": "src/api/client.ts", "summary": "Awaits the token before sending." }
]
},
{
"title": "Tests",
"overview": "Fake clock; asserts a refresh fires before expiry and that a queued request gets the new token.",
"diffs": [
{ "file": "src/auth/refresh.test.ts", "summary": "Timer and race coverage." }
]
}
],
"unplacedFiles": [],
"review": { "gitRef": "origin/main...HEAD", "base": "origin/main" },
"generator": { "engine": "claude-code", "model": "claude-sonnet-4-5" }
}
sections 之后的字段:
review.gitRef是读者看到的 diff 标签,请填写你实际进行 diff 的引用。base为可选字段。generator表示由谁编写指南:填写你正在使用的工具(engine),以及你知道的模型名称(model)。通常系统提示或启动工具时使用的模型会告知你。如果不确定,请省略model。读者会看到“由……生成”。此字段为可选。source(repo、branch、head)从 git 中读取。如果指南对应某个拉取请求,请添加"source": { "kind": "pr", "pr": { "url", "number", "title" } }。
3. 导出
plannotator guide export --guide guide.json --patch guide.patch
如果未安装 plannotator:curl -fsSL https://plannotator.ai/install.sh | bash -s -- --minimal(仅安装二进制文件,不安装其他内容)。
成功时会打印 HTML 文件的路径。失败时会以状态码 1 退出,并说明问题所在:文件不在 patch 中(会列出实际包含的文件)、文件被重复放置,或缺少字段。修正 guide.json 后重新运行。绝不要修改 patch 来迁就指南。添加 --out <file.html> 可选择文件保存位置。
告知用户文件所在位置。文件可通过磁盘路径或链接在任意浏览器中打开。
想要链接而不是文件?
plannotator guide share --guide guide.json --patch guide.patch
验证方式相同,但指南会上传到 guides.show,命令会输出一个 URL。默认情况下,上传内容采用端到端加密:托管方永远看不到代码,密钥是链接中 # 后面的部分,因此任何拥有完整链接的人都能阅读内容。命令还会输出一个删除令牌;将两者都提供给用户(plannotator guide unshare <id> --token <token> 可移除链接)。只有用户想要链接预览时才添加 --public(此时指南会以未加密的形式存储)。仅在用户要求链接时才分享;默认使用文件。