Write Spec — 行为规格 Skill
你的任务
把一个边界已经清晰的想法 / 需求,转化为一份可被验证的行为规格:
- 系统该有什么可观察行为 —— 用 Requirement + MUST 表达,每条都配 Scenario(WHEN→THEN)。
- 明确必须不发生什么 —— 把"不做什么"转成 MUST NOT 负向需求 + 可验证检查。
- 边界场景下如何表现 —— 边界值 / 空值 / 并发 / 幂等…… 逐项比对,适用的写成 Scenario。
- 怎么算做完了 —— 可执行的成功标准,不是"能用就行"。
刻意止步于此:不做技术选型、不画架构、不拆任务、不排期。 你的产出是一份"行为说清楚了、验收定死了、可以放心进入实现"的规格,而不是实现方案。
一句话:把"我们要解决 Y、做 A/B、不做 C/D、成功标志 Z"的概念,钉成"系统 MUST 这样、 MUST NOT 那样、在这些边界下表现如此、用这些可执行检查验收"的规格。
核心理念
spec 是编码前的最后一道闸门。需求里每一处没说清的行为、每一个没被表态的边界、 每一条沉默的"不做什么",都会在实现期变成返工、扯皮或上线事故。把它写成可被验证的契约,让"做完没做完"不再靠口头判断。
write-spec 不挖意图,也不给方案。 它只做一件事:把已清晰的概念,翻译成不会产生第二种理解的行为契约。
何时用 / 何时不用
适用:
- 概念已清楚,准备进入实现前,需要一份可验证规格。
- 要新增一个功能 / 能力,或要改既有功能,需要先写清"改成什么样、怎么验收"。
- 协作中需要一份"实现期可对照、验收时可逐条核对"的依据。
不适用(别硬套):
- 概念还模糊、意图不明确。
- 要的是技术选型 / 架构。
- 单行修复、错别字修正,或者需求已经非常明确、范围完全自包含的小修改。
- 已在写代码、定位 bug、做评审。
⚠️ 加载约束(硬性):本 skill 的产出必须经一个能实时 review 的活人确认才放行。 禁止在 CI / 定时任务 / 自治循环等非交互场景里把它当作"自动产 spec"的工具——那种场景遇到 "没有 spec",正确做法是把它标记为 blocker 并停下,而不是自动生成一份没人 review 的规格往下跑。
招牌机制:行为契约 + 双探针 ⭐
这是 write-spec 区别于"随手写个需求文档"的核心。一份 spec 不是把需求换种说法抄一遍, 而是让每条需求都过两关:
关一:可验证性
每条 Requirement 必须能写出至少一个 Scenario:WHEN <触发条件> → THEN <可观察的结果>。
- 写得出可观察结果 → 它是需求。
- 写不出(只能说"系统应该很好用 / 性能要好")→ 它是愿望,不是需求。打回重写成可观察的,或删掉。
检验:把 Scenario 交给一个不懂业务的人,他能照着判断"通过 / 不通过"吗?不能,就还没写清。
关二:双探针强制覆盖
光写"要做什么"会漏掉一半的真实需求——漏在边界上,漏在"不该发生什么"上。 两个探针逐项扫,把漏的逼出来:
边界探针(Edge Coverage) —— 逐项自问"这条适用吗?",适用的必须配 Scenario:
- 边界值(最大 / 最小 / 刚好越界)、空值(空输入 / 空集合 / null)、排序(顺序是否影响结果)、 并发(同时操作同一对象)、幂等(重复执行结果是否一致)、精度(浮点 / 金额 / 时间)、 编码(字符集 / 转义 / 二进制)、超时与失败(依赖不可用时)。
禁止探针(Prohibition Coverage) —— 把概念里每条"不做什么"转成可验证的负向需求:
不做自动同步→系统 MUST NOT 从 CI / 外部平台拉取或修改状态→ 验证:代码中不新增外部同步入口;UI 无同步配置项。- 关键:负向需求也要可验证。写不出"怎么检查它没发生"的,就还没转化完。
(两个探针的完整清单与"怎么把每一项转成 Scenario / MUST NOT",见 references/coverage-probes.md。)
greenfield 多一层:能力覆盖图(Coverage Map)⭐
双探针抠的是"选定要做的需求,其边界与不做什么"(微观完整性)。但 greenfield 还有
一个更靠前的漏洞:整类能力维度根本没被想到。Coverage Map 补这一层(宏观全面性)——
系统列出"这个功能 / 领域有哪些能力维度",给每个维度落一个档位
(纳入 / 默认不做 / 后续版本 / 必须确认),让全面性可被 review、漏项可被 catch;
再用"每行必落一档、不默认全纳入"防止全面滑向膨胀。
顺序是一个漏斗:先用 Coverage Map 圈定做哪些维度,再对纳入的维度用双探针抠边界。 (怎么列维度 / 判档 / 调研功能空间,见 references/coverage-map.md; brownfield 不建此图,走 delta。)
工作流程(阶段 0 + 四个工作阶段)
阶段 0 · 定位与上下文
- 扫项目: 如果你还没有了解代码库,那么先探索代码仓库,以理解代码库当前的状态。测试怎么跑(决定"成功标准"能落成什么形式的检查)、已有 spec / 文档、相关代码。
- 接上游:若存在需求概念文件(
docs/proposal/*或用户指明的位置),读入作为输入; 没有,就做一次轻量意图确认(确认"要解决什么、不做什么")。 - 判 greenfield / brownfield:
- 新增能力 → 写全量 spec。
- 改既有功能 → 用 delta:只写
ADDED Requirements/MODIFIED Requirements/REMOVED Requirements,不重写整个系统。
- 判规模:若这其实是多个独立能力,先提示拆分,逐个写 spec,别把一份 spec 撑成全系统说明书。
阶段 1 · 圈定能力维度并分级确认(greenfield 先建 Coverage Map)
brownfield:跳过调研与 Coverage Map——改动范围已被既有系统框定。只就答案能改变 spec 形状的少数关键点(关键验收口径、需用户拍板的边界取舍、范围硬边界)确认式提问, 进 delta 起草。
greenfield 分三步收敛,再起草:
1) 功能空间调研——调研与否由用户拍板(不是你) —— greenfield 起草前,"要不要先做一轮 功能空间调研"是一个 MUST 交给用户的决策。你主动、明确地问,给出你的建议(调研 / 跳过+ 一句理由),然后停下等用户回答,不得在用户表态前继续:
- 用户选调研 → 用 deep-research:聚焦①领域常见能力维度②按丰富度分档③哪些易漏却会改变 spec 形状。铁律:产出是功能空间参考,不是需求,一项都不默认纳入。
- 用户选跳过(或一开始就说了不调研)→ 凭需求 + 自身知识自列维度,spec 里注明"未调研"。
- 调研选了却跑不起来(deep-research 工具缺失 / workflow 失败 / 无网络)→ 不卡在反复重试: 如实告知用户"调研因 X 失败",降级为凭领域知识自列维度(spec 注明"未调研:原因"),继续建 Coverage Map;是否另寻调研方式由用户定。
- 本次属于有成熟功能空间、易漏整类能力的领域(权限 / 通知 / SSH 运维 / 支付 / 导入导出…)时, 调研价值高,更要问——别因"需求看起来够详尽"替用户跳过。
2) 建 Coverage Map —— 把"需求已含 + 调研补充"的能力维度 汇成一张表,每行必落一个档位:
- 纳入 → 阶段 2 写成 Requirement + Scenario。
- 默认不做 → 写成 MUST NOT 或在覆盖表标注(可被 review 反对)。
- 后续版本 → 进覆盖表 + 待解问题。
- 必须确认 → 按第 3 步分级。
不默认全纳入——每行都有收敛决策。
3) 分级确认(别一次抛几十个问题) —— 对需澄清的点分三级:
- 现在问:答案会改变 spec 结构(核心数据模型 / 主流程 / 范围硬边界)→ 现在聚焦提问,一次一问或小批量。
- 采用默认:不影响主方向 → 记"采用保守默认:X",不打断。
- 放 Open Questions:重要但不阻塞本版 → 进 spec「待解问题」。
检验:「这个问题不问,spec 能不能起草?」能 → 它不是"现在问"。
列维度 / 判档 / 调研的完整清单见 references/coverage-map.md。
阶段 2 · 起草 spec(行为契约)
按 references/spec-template.md 写:
- 背景 / 范围(简短):为什么做、覆盖什么、显式不覆盖什么。
- 能力覆盖与档位(greenfield):把 Coverage Map 以精简表落盘,让 review 一眼看到哪些做 / 不做 / 为什么;纳入项对应到下面的 Requirement。
- 行为需求:Requirement + MUST/SHALL + 每条配 Scenario(WHEN→THEN)。brownfield 用 delta 标注。
- 不做什么(MUST NOT):禁止探针的产物,每条配可验证检查——优先写用户可观察的行为(如"UI 无编辑入口""不返回被禁数据");代码 / 依赖检查("无写库路由""无引入某库")只作验收辅助,除非"不得引入某类外部调用 / 持久化 / 网络行为"本身就是产品 / 安全约束。
- 边界场景覆盖(索引):把边界探针逐项映射到对应 Requirement / Scenario;行为只写在 Scenario 里,本节不重复写行为,只做覆盖核对。
- 成功标准:可执行的检查(最好能对应到"怎么跑测试")。
- 待解问题:还没定、但需要记录的点。
纯行为:不写技术选型 / 架构 / 数据模型 / 任务(行为级约束例外——如 "MUST NOT 引入外部网络调用"这种可验证的行为约束,属于 spec;"用 Redis 做缓存"这种技术选型,不属于)。
阶段 3 · 自检(双重,落盘前过一遍)
① spec 卫生:
- 占位符 / TODO / 没写完的节?补全。
- 自相矛盾?(两条需求打架、Scenario 与 Requirement 不一致)
- 范围过大?需要拆成多份?
- 歧义?(任何一条能有两种解读 → 选一种写死)
② 覆盖自检(双探针回扫):
- 每条 Requirement 都有 Scenario 吗?
- 边界探针逐项过了吗?适用的都写了吗?
- 概念里每条"不做什么"都转成 MUST NOT 了吗?
- 成功标准是可执行的吗?
- (greenfield)Coverage Map 每行都有唯一档位、无"待定"残留;"纳入"都成了 Requirement、关键"默认不做"都成了 MUST NOT 吗?
- (greenfield)有没有把调研维度无脑全纳入(膨胀)?
就地修复,不必重复 review。
阶段 4 · 用户 review 门禁
- 落盘:把 spec 写入仓库(默认就写文件——spec 是要进仓库、实现期持续更新的工件)。 位置见下文「产物与落盘」。
- 请用户 review,并明确这条规矩:
未通过 review 的 spec,不得采用。
- 用户要改 → 回阶段 2 / 3 修订并重过自检;用户显式确认 → 过门。
- 过门后:不自动调用其他skill、不开始写代码。本 skill 到"规格确认"为止。
哪些回答不算 "yes":
- "你看着办 / 都行" = 委托,不是决策。
- "听起来不错" = 模糊回应。
- 沉默后一句"那就开始吧" = 放弃,不是确认。
产物与落盘
- 默认单份文档,内容是行为契约(Requirement / MUST / Scenario / MUST NOT / 边界 / 成功标准)。
- 位置:跟随仓库既有 spec 约定——若已有
docs/specs/,就跟随; 否则默认docs/specs/<YYYY-MM-DD>-<主题>-spec.md(目录不存在先跟用户确认)。 - brownfield 用 delta,只写这次改了什么。
- 规模极大 / 多能力时,可提议拆成 per-capability 多文件,但这是 scale-up,不是默认。
核心原则(不要违反)
- 行为契约,不是需求复述 —— 每条需求都要能写出可观察的 Scenario。
- 先扫上下文,再写 spec —— 脱离代码库(尤其"测试怎么跑")的 spec 是愿望清单。
- 双探针是强制项 —— 边界与"不做什么"是漏需求的两个重灾区,逐项扫,别省。
- "不做什么"要可验证 —— MUST NOT 也得能检查它没发生,否则没转化完。
- 纯行为,不越界到方案 —— 技术选型 / 架构,任务拆解都不在预期范围内;只有"行为级约束"留在 spec。
- 未过 review 不放行 —— spec 是编码前闸门,显式确认才能呗采纳使用。
- 止步于规格,不自动往下 —— 不调用下游 skill、不写代码。
- (greenfield)先圈维度,再抠边界 —— 用 Coverage Map 系统覆盖能力维度并逐项定档,防漏整类功能;但每行必落一档、不默认全纳入,防全面滑向膨胀。
- (greenfield)调研与否,用户拍板 —— 是否做功能空间调研是用户的决策:主动问、给建议、等回答;绝不以"需求够详尽 / 已有发散材料"替用户跳过,被动语气("要不要你说")不算问。
终止条件(可检验)
- 达标即停:当每条 Requirement 都有 Scenario、双探针都过、"不做什么"都成了可验证 MUST NOT、 成功标准可执行——spec 就够了,进入 review 门禁,别为"更完整"无限加需求。
- (greenfield)覆盖到位即停:Coverage Map 每行都有档位、纳入项都落成 Requirement,即视为覆盖到位;不为"更全"把"后续版本 / 默认不做"的维度硬塞进本版。
- 兜底:如果发现概念本身还没清(写到一半发现"要解决什么"都说不清),停下来, 别用 spec 的外壳硬包一个没想透的想法。
反例(不要这样做)
❌ 把概念单换种措辞抄一遍当 spec —— 没有 Scenario、不可验证。 ❌ 写"系统应该性能好 / 体验流畅"这种无法判断通过与否的"需求"。 ❌ 只写"要做什么",跳过边界探针和"不做什么"——漏掉一半真实需求。 ❌ "不做什么"只写一句"不做同步",没给"怎么验证它没发生"。 ❌ 在 spec 里写"用 React + SQLite""加一个 Redis 缓存层"——越界到技术方案。 ❌ (greenfield)只照需求明说的功能写 spec,整类能力维度(权限 / 空态 / 批量 / 导出…)静默漏掉。 ❌ 把功能空间调研结果当需求,所有维度全纳入——spec 膨胀成"全行业功能大全"。 ❌ 一次性把几十个澄清问题全抛给用户,不分"现在问 / 采用默认 / 放待解"。 ❌ (greenfield)自己判断"需求够详尽 / 已有发散材料"就跳过功能空间调研——跳不跳过是用户的决策,必须主动问、等用户拍板("你觉得需要再说"不算问)。 ❌ deep-research 跑不起来(缺工具 / 无网 / workflow 失败)却反复重试、卡死——应如实告知 + 降级凭领域知识自列维度继续,别卡在工具错误里。 ❌ 改一个小功能却重写整个系统的 spec —— 该用 delta。 ❌ 动笔前不看代码、不看测试怎么跑,写出一份脱离代码库的愿望清单。 ❌ 没落盘、没让用户 review 就说"spec 好了,开始写代码"。 ❌ 概念其实还没想清,却用 spec 的外壳硬包着往下冲 —— 停下来。 ❌ 在 CI / 自治循环里自动产 spec,没有活人 review。
相关参考
- references/spec-template.md —— 行为契约 spec 的落盘模板 (含 delta 写法,Requirement / Scenario / MUST NOT / 边界 / 成功标准各节)。
- references/coverage-probes.md —— 双探针完整清单: 边界探针逐项 + 禁止探针,含"怎么把每一项转成可验证的 Scenario / MUST NOT"。
- references/coverage-map.md —— 能力覆盖图(greenfield): 功能空间调研(先问后调)、能力维度定档(纳入 / 默认不做 / 后续版本 / 必须确认)、问题三级分流。