design-doc 是做什么的?
gemini-4-argon 负责编写和修订所有散文,包括摘要、易懂描述(plain twins)、句柄、修订说明和发布文本。会话将事实和规则(写作契约、反垃圾信息规则、长度限制)通过 gemini -m gemini-4-argon --skip-trust -p 传递给它,逐字存储回复,并自行收集证据和发布结果。散文助手通过 gemini --skip-trust -p 调用同一个模型,且没有备用模型。
架构设计是一系列构建在假设之上的决策堆栈。此技能以对话形式运行设计过程——用户决定一切——并将结果渲染成一份文档,其中每个主张都可追溯到其假设、决策以及产生它的问答轮次。
一个命令驱动所有机械部分:
TOOL="python3 ${CLAUDE_PLUGIN_ROOT}/skills/design-doc/scripts/design.py"
$TOOL scaffold --title <名称> # 为此设计文档创建一个新的 ./<slug>/ 目录
$TOOL scaffold --example # ./tinyq/,一个已填写的小型工作示例
$TOOL check <目录> # 检查注册表、易懂描述、图表源码和摘要面板的错误;非零退出表示错误,--strict 会将阻止发布的警告视为错误
$TOOL summary-text <目录> # 将面板以 Markdown 格式输出,每个 ## 章节一个面板;这是门控(gates)的输入
$TOOL plainify <目录> [--only DQ3,A2] [--dry-run]
$TOOL glossary <目录> # 找出散文中使用但词汇表缺失的术语,作为候选条目
$TOOL build <目录> # 将 components/*.tsx 编译成 components.js;仅用于包含 components/ 目录的文档
$TOOL render-check <目录> # 在 Headless Chrome 中渲染每个 Mermaid 图块;解析错误或页面异常时失败
$TOOL pdf <目录> # 通过模板的打印样式表将文档打印到 <目录>/design-doc.pdf
$TOOL snapshot <目录> --note "…" --item "…" # 创建一个修订快照,用于变更历史对比;note 是面向读者的标题,每个 --item 代表一个变更
$TOOL links <目录> [--fetch] [--missing] # 列出每个决策和未决事项中的拉取请求链接及其状态;--fetch 向 GitHub 查询每个链接是否已合并并报告差异,--missing 列出尚未链接的条目
在阶段 1 之前阅读 reference/method.md,在阶段 5 之前阅读 reference/writing.md,在阶段 6 之前阅读 reference/publish.md——方法文件是轮次/注册表协议,写作文件是语气合约,发布文件是托管流程。reference/schema.md 是 JSON 文件逐字段的合约;当需要一个完整的注册表示例时,可以搭建 tinyq 示例。
术语
- 注册表 (Register) —
registers.json中的一个结构化列表,其条目具有稳定 ID:A#假设、DQ#决策、Q#未决问题、V#Spike、c-<slug>架构卡片。 - 轮次 (Round) — 向用户提出的一套问题,逐字记录在
qa-log.json中。一轮同时询问所有未决分支,每个分支作为一个design-doc.fork块,不询问其他内容。导致新分支的答案会开启下一轮,同样一次性提出;qa-log.json按顺序记录轮次,以便后续板面可以依赖先前的答案。 - 替代 (Supersession) — 变更的决策会获得一个新条目,旧条目标记为
s: "superseded"并添加一个by指针,文档会将其渲染为“已被替代”以及后续决策的标题。历史记录保持清晰,因为没有任何内容被原地编辑。 - 星标 (Star) (
★) — 标记承载关键假设的条目,其失败将使整个文档失效。 - Spike — 一个有命名的、有时间限制的实验 (
V#),用于将标记为(E)的估算转化为经过测量的数字。 - 执行摘要 (Executive summary) —
summary.html,一个手写的 HTML 片段,与registers.json并列。对于只看摘要的读者:默认为一个全屏面板的集合,当设计只是一个想法和一个图表时,则只有一个海报。从不作为数据解析;check会检查其结构、字数预算和引用。 - 易懂描述 (Plain twin) — 条目旁边
p字段中的内容,一两句简短的句子,向不愿细读的读者解释该条目的含义。文档默认显示易懂描述,并通过一次切换即可查看精确措辞。 - 关键点 (Key) 和 主题 (Theme) —
key: true标记文档开头作为卡片展示的 3-8 个决策和假设;theme将每个条目归入设计的 3-5 个主题之一,这些主题在阶段 0 中命名并定义在themes图中。 - 图表 (Diagram) — 系统图的 Mermaid 源码,位于
diagram注册表键中;文档渲染它,读者可以平移和悬停查看,请求路径可以逐步遍历它。diagram.overview是“概述”卡片绘制的十个节点子集,完整的图则可通过一次点击访问。手绘的sysd.svg作为diagram.kind: "svg"仍然有效。 - 句柄 (Handle) — 每个决策、假设、未决事项、架构卡片和数字表上的
h字段:读者会怎么称呼它,两到五个词。引用和芯片行显示句柄;ID 存在于悬停卡片中。 - 组件 (Component) — 声明在
components图中的交互式图形(dd.tabs、dd.before-after、dd.whatif、dd.steps、dd.timeline、dd.matrix、两个比较面板dd.flow和dd.lanes、手绘系统图dd.system,以及用于嵌入已发布架构文档的dd.arch),通过 ID 放置到面板或条目上;components/下的 TSX 文件是build编译的逃生口。 - 图形简介 (Figure brief) 和 批评 (Critique) — 面板从中抽取并与之对照阅读的两个 NOTES.md 部分。简介在每个图形绘制前编写,每图五行的结构:它要表达的观点,它服务的决策 ID,能表达观点所需的最小视图,它省略了什么,以及它使用的真实标签。它的前两行会成为
<figcaption>。批评是在每个面板、图形、表格和统计数据之前编写的,每行一个:它服务的决策,它做出的主张,读者可能留下的疑问,以及修复或删除的建议。当缺少任一标题时,check会发出警告。 - 链接 (Link) — 决策、未决事项或发现行上的
links[]条目:实现它的拉取请求、问题、提交或文档。未决事项链接上的closes: true标记了将其终结的那一项。文档将每个链接显示为一个带有 GitHub 状态的芯片,并在每个未决事项分组前显示已关闭项目的数量。 - 状态 (Statuses):决策的状态为
resolved | superseded | open,文档渲染为“已决定”、“已被替代”和“仍待定”;假设的状态为working | validate,渲染为“已假设”和“待确认”(需要文档外的人确认)。未决事项的状态为open | closed,渲染为“仍待定”和“已关闭”;一个已合并的closes链接会在s字段声明之前关闭一个条目。散文使用渲染后的词语,JSON 使用值。
范围
此技能以设计为边界。其产出是一份决策记录和一份文档;实施代码是不同的任务,在提案通过评审后开始。四个门控机制确保记录的真实性:
- 设计分支由用户决定。每个分支都必须经过一轮问答,即使某个选项看起来明显正确:记录为什么比节省的几轮对话更有价值。
qa-log.json是逐字且只增不减的。可以清理答案中的拼写错误,但不得改变任何实质性内容,并跳过纯解释性的交流;它是决策日志,而非对话记录。- 对抗性评审的产物不进入最终的渲染文档。只有它所驱动的决策才会发布;发现结果部分读起来像是自我吹嘘,对读者毫无价值。
- 文档不包含虚荣计数(“27 个条目”、“9 个未决 Spike”)。数字只在描述系统时出现,而非描述工作本身。
阶段 0 —— 搭建与诊断
运行 $TOOL scaffold --title <名称>。每个设计文档都位于自己独立的目录中——scaffold 会创建 ./<slug>/(通过传递一个显式路径作为位置参数可将其放在其他位置),并拒绝非空的目标目录,因此一个设计永远不会与另一个设计的文件或现有项目文件混淆。在提出任何方案之前,先就当前系统与用户面谈:存在什么,痛点在哪,原因是什么。将诊断结果以根因而非症状的形式写入 NOTES.md(“持久化延迟就是 S3 延迟”,而不是“写入慢”)。诊断结果绝不上板:直接写入 NOTES.md,用户在渲染的文档中审阅,他们提出的任何更正都以他们自己的话被合并进去。在诊断结束时,给出一个执行摘要所依赖的分类:是对现有系统的变更,还是除了需求之外一无所有的全新。同时命名设计的 3 到 5 个主题(“存储”、“调度”、“租户”):它们会成为决策和假设归入的 themes 图,而那些诊断无法命名的主题,就是设计不存在的主题。针对错误的诊断进行设计,会浪费所有后续阶段。
退出标准: 项目目录已创建;用户在渲染的文档中阅读了诊断结果、变更/全新分类及主题,并表示同意。
阶段 1 —— 假设
在第一轮问答之前,检查可用技能列表中是否有 cc-present:present(/cc-present 板技能),如果有,则使用技能工具调用它;面谈从第一个问题开始就作为实时板运行,cc-present:present 不存在时才使用 AskUserQuestion 作为后备。此插件自带其块包——运行 cc-present pack list 并阅读 design-doc 的参考片段;其 design-doc.fork 块是面谈界面,也是面谈板唯一携带的块。
直接将假设写入 registers.json;没有板来确认或质疑它们。绝不在用户面前放置 design-doc.claims 块、确认/质疑扫描或注册表转储:用户在渲染的文档中审阅假设,他们提出的任何更正都以他们自己的话被合并进去。如果设计需要做抉择才能继续的假设,那便是一个分支,并将在阶段 2 的板中作为 design-doc.fork 块提出。从诊断面谈、代码以及用户已说过的话中收集基本事实:设计必须满足的约束,关于规模和负载的事实,用户相信但尚未验证的事情。每条变成一个状态为 working 或 validate 的 A# 条目;用星号标记承载关键假设的那一个,并将每个 validate 条目的确认方记录为未决事项。当用户标记一个假设为不可靠时,该标记会放入条目中;代表他们解决该问题,将违背注册表的目的。
退出标准: 用户在渲染的文档中审阅了假设,且它们覆盖了用户所知的一切;$TOOL check 通过。
阶段 2 —— 设计轮次
通过问题轮次进行设计。面谈是一个 cc-present 板,同时提出所有未决分支,每个分支作为包含丰富选项的 design-doc.fork 块:每个选项附带后果、优缺点、恰好一个推荐选项,以及一个未决列表的逃生口。板只携带分支块,没有其他内容。任何非分支的内容都是缺陷:design-doc.claims 块、确认/质疑扫描、design-doc.registers 转储或上下文块。分支自身的问题、后果以及优缺点承载了其所需的上下文。开启新分支的答案会进入下一个板,以相同方式构建。
轮次在实时的 cc-present 板上运行:在第一轮之前(在阶段 1 和此处都需检查),检查可用技能列表中是否有 cc-present:present(/cc-present 板技能),如果有,则使用技能工具调用它——其指令负责指导如何组成和推送板,此后每一轮都通过板进行。一个分支是一个 design-doc.fork 块,其选项内联地携带后果,逃生口返回 {defer: {title, why}}:由人来命名未决问题,因此 Q# 着陆时无需再花费一轮询问如何称呼它。当块包缺失时,一个普通的 choice 块手动携带相同的结构——每个选项都有后果描述,恰好一个标为“(推荐)”,以及最后一个选项“添加到未决列表”,实际上会入队一个 Q#——而 AskUserQuestion 是最后的手段,仅在 cc-present:present 不在技能列表中时使用。当板技能存在时,设计分支绝不会通过 AskUserQuestion 进行。将每个分支作为一个普通问题来问,让人可以冷启动回答(“工作节点应该如何接收任务?”)。它所解决的注册表 ID 放在块的 decides 字段中,或跟在 AskUserQuestion 的 header 后面,绝不写在问题文本中;选项的后果说明会发生什么,而不是哪个条目被它取代。轮次是面谈,而非调查:指出当前草稿中的缺陷,建议用户未提及的替代方案,在证据不符时提出异议,并且自己不做任何决定。每个答案成为一个带有决策结论、被拒绝的替代方案以及轮次编号的 DQ#。当后续轮次更改了先前的决策时,进行替代:创建一个新的 DQ#,并在旧的条目上添加 by 指针。
退出标准: 未决列表外没有未决定的剩余分支;每个 DQ# 都可追溯到 qa-log.json 中的某一轮。
阶段 3 —— 对抗性评审
在润色使缺陷更难发现之前,攻击中间草稿。当 codex 插件技能可用时使用它;否则,生成一个全新上下文的子代理,与设计无利害关系,并以怀疑的高级工程师身份负责攻击:正确性错误、缺失的故障模式、无依据的数字。将输出逐字保存为 <评审者>-review-<日期>.md,将每个发现索引到 findings 注册表中(仅数据,从不渲染),并处置每一个:一个新决策、一个未决事项、或一个记录在案并附有理由的拒绝。由代码修复的发现,将修复它的拉取请求作为行的第五个元素,格式与 links[] 条目相同。需要用户决定的发现,则像其他任何轮次一样,其问题说明评审者发现了什么,使用评审者自己的话;发现编号...