docs-update 是做什么的?
文档无声地腐烂:没有失败,只是文字不再真实。这个技能找到最近变更应该触及的文档,并使它们与代码保持一致。
下面的命令完整拼写了 ~/.claude/skills/docs-update/scripts/。严格按原样运行它们——保留开头的 ~,不要展开它。 权限规则匹配文字命令字符串,因此 /home/<你>/.claude/...(波浪号展开后)、python3 ~/...、相对路径以及先 cd 再执行在字符串层面上都是不同的,每个都会重新触发权限提示。波浪号路径不是“非正式的绝对路径”——对权限规则而言,它就是路径。
文档随变更一起发布,而不是之后。 如果你在功能分支上,请将文档提交到该分支上,这样合并时就会带上它们。一个后续的文档 PR 是没人会写的 PR。
1. 选择范围
按优先级排序:
用户明确指定。 “全量扫描”、“从 v2.1 开始”、“仅此分支”——直接使用。全量扫描是 --full,读取所有内容;当长时间未更新或首次在仓库应用此技能时,这是正确的选择。
文档记录了自己的最后更新时间点:
~/.claude/skills/docs-update/scripts/docscheck.py markers
如果某个文档包含 Last updated: <日期|提交哈希>,则从该点开始对该文档进行范围限定(--since)。不同步的文档会获得各自的范围,没有统一答案。
否则,从 Git 自动推导:
~/.claude/skills/docs-update/scripts/docscheck.py scope
它优先选择最后合并的分支(一个分支的工作量是人们通常理解的最小单位),回退到最后提交。使用 --since <引用> 可覆盖。
本次会话完成的工作 是脚本无法感知的情况。如果本次会话做了更改,你已经知道哪些文件被改动了;将会话开始前的引用作为 --since 传递,或者使用你自己的编辑列表。
scope 将结果分为 kind=code 和 kind=doc-already-touched。第二个列表很重要:那些文档是与变更一起更新的,所以需要检查它们的正确性,而不是检查是否有遗漏。
2. 找到变更实际触及的文档
~/.claude/skills/docs-update/scripts/docscheck.py impacted
对于每个更改的代码文件,该命令报告那些明确提及该路径的文档。引用你修改的文件的文档最有可能描述不再正确的内容,这比重新阅读所有文档好得多。
它只匹配完整路径。匹配父目录听起来更全面但实际上没有用:在单体仓库中,apps/web-nuxt/ 出现在 55 份文档中的 62 个地方,所以所有内容都会影响所有内容。
result=none 是正常现象,并不意味着“无事可做”——它表示没有文档提及这些路径,所以应该根据主题来判断。这就是步骤 3 要做的事。
3. 根据主题判断,使用仓库自身的文档分类法
impacted 找到路径引用。它无法找到那些描述你更改的行为但没有提及文件名的文档。因此,阅读变更内容并思考其含义。
首先了解这个仓库如何组织文档——brain/、docs/、CONTEXT.md、ADR 目录——并遵循那种结构,而不是自创一种。如果项目技能(.claude/skills/*)涵盖了文档说明,则以此为准。
常见映射关系:
| 变更类型 | 对应的文档 |
|---|---|
| 新的用户可见功能 | 功能文档 + 其目录/索引行;README 功能列表 |
| 修改现有行为 | 该功能的文档 |
| 模式、认证、构建、存储、实时通信、提供商 | 对应的架构文档 |
| 非显而易见的决策或在审查中提出的决策 | 决策/ADR 日志,包含其理由 |
| 新术语 | 术语表 |
| 新增或修改的环境变量、命令、脚本 | README 以及任何设置/运维文档 |
| 新增依赖 | 任何技术栈/技术列表文档(这些是手工维护的,常常被忘记——对比清单文件) |
| 用户可见的变更 | CHANGELOG [Unreleased] 部分 |
两个陷阱:
- 嵌入在散文中的衍生事实。 说“当前版本是 2.16.2”或列出技术栈的文档是其他已变更内容的副本。请对比真相来源(清单文件、版本文件),而不是相信散文。
- 本应是历史或愿景的文档。 CHANGELOG 条目、TODO 和 ROADMAP 引用了已删除或从未编写的文件。不要“修复”它们。
4. 检查引用是否仍然有效
~/.claude/skills/docs-update/scripts/docscheck.py links
两种类型:
kind=link- 目标已不存在的相对 Markdown 链接。始终是真正的问题。kind=source- 不再存在的内联代码路径,通常是因为文件被移动或重命名。叙事文档被排除在外,大括号展开、<占位符>、通配符和.gitignore中的构建输出也被过滤,因此剩下的是值得检查的。
修复范围内的问题。仓库其他位置的发现值得报告,但不要让工作悄然扩大到全量扫描。
5. 写作
清除你写的所有内容的废话
对每一行新增或修改的内容应用 unslop 技能。 文档是废话造成最大伤害的地方:它被正在学习的人阅读,是新接触者遇到的第一件事,而且不像聊天消息那样会过时。
在文档中常见的标志:
- 开场白式的废话。 “本文档概述了……”、“在本节中,我们将探讨……”。删除它们,直接陈述事实。
- 用散文重复代码。 “
getUser函数获取一个用户。”如果这句话只是标识符的英语翻译,那就毫无价值。写出代码无法表达的内容:约束、理由、注意事项。 - 空洞的强调词:全面、健壮、无缝、强大、灵活、简单、轻松、仅仅。“只需运行 X”当 X 并非简单时就是错误的。
- 在答案确定时使用模糊措辞:“通常”、“一般”、“应该正常”。要么是确定的,要么取决于可命名的条件——请明确命名。
- 提醒式填充:“值得注意的是”、“请注意”、“牢记在心”。它后面的句子才是内容;直接输出那个。
- 总结页面上方内容的摘要部分。 如果文档需要回顾,说明它太长了。
- 重复名称的描述列。 表格行
| --verbose | 启用详细输出 |浪费了一行且没有提供任何信息。 - 三点规则的填充——为了节奏而添加的第三个示例,但实际上与前两个没有区别。
匹配文件本身,而不是废话
匹配文件现有的语气:时态、密度、条目是单行还是散文。如果文档中一个部分突然读起来风格不同,比整份文档风格一致但过于简练更糟糕。
这两个规则仅在现有文档本身就很随意时冲突。此时:匹配它的结构和密度,而不是它的填充内容,并且不要重写你没有修改的部分。 同时更新文档和重新排版整个文件会生成无法审查的差异,并且埋没了真正重要的变更。如果某个文档需要整体修改文风,请说明并提供单独的任务。
其他要点
- 链接源路径而不是重复代码,这样下一次变更会破坏链接,而不是悄悄地与散文矛盾。
- 用现在时描述当前真实情况。文档不是变更日志:“我们用 Y 替换了 X”属于 CHANGELOG,“系统使用 Y”属于文档。
- 如果文档有最后更新标记,请移动它。
6. 报告
- 使用的范围及其原因
- 更新的文档及每份文档的变更内容
- 检查过但故意未修改的文档
- 范围外发现的损坏链接或引用,列出但不修复
- 任何无法在没有用户的情况下判断的内容