输出语言:用户显式指定(含平台语言设置)优先,其次跟随近期对话,否则使用英语。新产物使用创建时语言,增量修改沿用原文语言;固定话术按语义表达。
插件根:
${CLAUDE_PLUGIN_ROOT}——本 skill 正文与其 references 中的插件根命令以此为准;若上式仍为变量字面量(平台未替换),按 requirement-analysis 的 references/exploration-patterns.md「插件根解析」序列推导。
外部搜索统一入口:外部检索先用 anysearch;不可用时按搜索与降级规则执行。
编写实施计划
概述
假设执行计划的工程师能读到仓库、但不了解本次设计的取舍:技术过硬,会用工具链,但不知道我们为什么这样改。计划写清每个任务动哪些文件、改动要点、关键 diff 片段、怎么验证、参考哪些文档;不替执行者抄写他能自己读到的现行文件。DRY、YAGNI、TDD、频繁提交。
开始时声明:「我正在使用 writing-plans skill 编写实施计划。」
动笔前确认:编写计划须持有用户的明确同意——用户本轮显式指示编写计划、或上游流程已代为确认(requirement-analysis 阶段 8 的前置确认)时视为已同意、不重复问;除此之外(如隐式触发、只收到一个 spec 路径)先确认「基于 <spec 路径> 开始编写实施计划?」再动笔。
计划保存至:spec 所在特性目录的 plan/ 目录——plan/index.md + plan/tasks/TNN.md + plan/progress.yaml 三件套(唯一生成形态,结构见下文「plan 目录结构」节);特性目录由 requirement-analysis 在写 spec 时按同日序号命名规则创建;无 spec 输入的独立触发则自建特性目录。用户对计划位置的偏好优先于此默认值。
唯一分文件形态:每份计划(不论任务数多少)都产出 plan/ 三件套;progress.yaml 是唯一状态源,任务文件与 index 内不使用复选框跟踪。存量单文件计划(plan/*-plan.md)由 executing-plans 按原样读取执行(读宽容),本 skill 不再生成该形态。
Spec 状态检查:载入 spec 时读其 frontmatter 的 spec_dev.status——仍为 draft 时说明漂移守卫尚未激活(requirement-analysis 阶段 8 的激活动作未执行,常见于跨会话独立触发):与用户确认 spec 已定稿后,把 status 翻为 active 并单独 commit,再开始编写计划;不翻转则守卫对该特性静默失效。为 superseded 时停下告知用户该 spec 已被取代(附 superseded_by 指向,指针缺失或悬空时说明"无可达后继";沿指针链跳转时记录已访问路径,链上出现环则列出环上文件并停止),经用户显式确认才可继续按旧 spec 编写计划;正文带 Superseded-pending 标注时向用户提示「该 spec 正被 <新 spec> 取代中(待交付)」后再继续。无 frontmatter 的旧版/外部 spec 跳过本检查。
上下文:编写计划阶段不建工作区——隔离以固定的「任务 0」写入每份计划,执行时才运行(见下方"任务 0")。
范围检查
spec 聚焦单一交付物(绝大多数情况)→ 本节零动作。若 spec 覆盖多个独立子系统、或含阶段化结构("第一阶段/Phase 1/先做 X 再做 Y"),这本应在需求设计阶段拆成子项目并登记 roadmap(requirement-analysis 的范围分解检查);发现没拆时:
- 首选回炉:建议回 requirement-analysis 补分解——spec 收缩到第一个子项目、其余登记
.spec-dev/roadmaps/,然后只为收缩后的 spec 编写本计划 - 用户不回炉:只为第一个子系统/阶段编写本计划,剩余范围当场登记 roadmap(
.spec-dev/roadmaps/YYYY-MM-DD-NN-<project>.md,无则新建:frontmatterspec_dev_roadmap(version/project/status: active)+ 子项目表(序号/名称/一句话范围/依赖/状态/特性目录),本子项目行记in-progress、剩余行记pending)并 git commit——被延后的范围必须有落盘登记,不允许只活在对话里
不变式:一次只写一份计划,不为未实施的后续阶段预写计划。计划要求每步含关键 diff 片段与精确路径,后续阶段的代码建立在前一阶段尚不存在的产物上——现在写出来必然失效。后续子项目在前置交付后按 roadmap 续接(executing-plans 收尾会核对 roadmap 并提示下一个)。
任务分解与方案形态遵循 design-principles.md 八条设计原则;同时按实际问题使用其「模块判据」。原则违反时重划;启发式须有证据,不为凑 adapter 数量新建抽象,不否决已批准 seam。计划头部保留八原则声明并引用该判据定义点。
文件结构先行
宽面机械迁移先尝试普通独立验证任务;不成立时 expand 保留新旧形、按实际影响范围分批 migrate、最后 contract 删除旧形,每批通过相关验证再提交;必要的安全顺序仍写依赖。连批次都不能独立通过时,记录证据并采用下方多票集成组。识别解除实际实施阻碍的前置重构,有需要才安排 T01,T00 固定隔离;无需要不制造空重构票。
定义任务前,先画出将创建/修改的文件清单及各自职责——分解决策在这里锁定:
- 单元边界清晰、接口明确,每个文件一个职责
- 你对能一次装进上下文的代码推理得最好,文件聚焦时编辑也更可靠——偏向小而聚焦的文件
- 一起变化的代码放在一起:按职责拆分,不按技术分层拆分
- 既有代码库跟随既有模式;正在改的文件已经臃肿时,把拆分纳入计划是合理的,但不做无关重构
该结构决定任务分解:每个任务产出自包含、独立可理解的变更。
拆任务前读取 从 spec 到可并发任务图:先确认共享契约与测试边界,再划可独立验证的功能切片,区分真实依赖和写入/资源冲突。将准备结论写入 index,并为所有具备条件的实施票生成并发声明,包括依赖链上的票;用户授权执行后默认按该图调度。生成计划本身不授权实施,明确串行要求仍须保留。
任务的粒度
任务是携带独立测试周期、值得一次独立审查的最小单元。功能票优先按一条完整可观察行为纵向切分,贯穿该行为实际需要的层;不按“所有数据库→所有 API→所有 UI”制造整层串行,也不强迫无 UI 的功能包含 UI。把配置、脚手架、文档步骤折叠进需要它们的任务;只在"审查者可能拒绝一个任务而通过相邻任务"处切分。每个任务以一个可独立验证的交付物收尾;必要前置重构和机械迁移沿既有类型处理。
步骤是一个动作(2-5 分钟):
- 「写失败测试」——一步
- 「运行确认失败」——一步
- 「写最小实现」——一步
- 「运行确认通过」——一步
- 「提交」——一步
TDD 循环的完整纪律遵循 test-driven-development skill——普通行为任务显式内嵌上述五步;批准的纯重构、集成组成员和组验证票按下文类型化步骤写全操作、验证、提交及真实结果。
Scenario 直译为验证:每个 #### Scenario: 都有实际验证步骤;行为变化翻译为有效失败测试,纯重构使用前后保护,组内不能独立通过的相关验证明确归属组验证票,不漏掉 Scenario。映射固定:GIVEN→arrange(构造前置状态)、WHEN→act(触发动作)、THEN→assert(断言可观察结果);测试名沿用 Scenario 名。规范到测试零翻译损耗——不要自己另编测试场景后把 Scenario 丢在一边。测试步骤的 Lane 归属与 DB/前端/Agent 处方遵循 test-strategy skill(矩阵行标注的 lane 直接继承;DB 类步骤对照其 references/db-testing.md,不得出现每测试一容器)。
plan 目录结构
每份计划的产物三件套结构:
.spec-dev/<特性目录>/plan/
├── index.md # 头部 + 全局约束 + 相关测试范围 + 设计原则块 + 任务导航表;不复制任务正文
├── tasks/T00.md … # 每任务一文件,正文结构与下文任务模板逐字一致(文件块/接口块/TDD 五步)
└── progress.yaml # 唯一运行时状态
按动作读取
| 动作 | 必读资料 | |---|---| | 写头部、任务导航、scopes、绑定与唯一进度 | 计划格式;编写任何新计划前读取 | | 写 T00、普通行为票或纯重构票 | 任务模板;将代码、命令、预期与接口写入产物 | | 从 spec 划任务、判断哪些票能独立推进 | 并发准备;核对共享契约、纵向切片、依赖理由和共享写入 | | 声明不可独立验证的集成组 | 集成组声明;无组不加载 | | 声明可派发实施票 | 并发声明;写集合仍只在 scopes,声明不等于开始实施 | | 写独立 final F、验收 A 和最大号交付 D | 验收与交付模板;保留 F→审查→A/对账→D 顺序 | | 草稿 Self-Review 与恢复修订 | 计划自检;核对实际状态提交与资源归属 |
工具、片段和失败分支必须进入生成的计划;链接用于取得定义,不能代替执行步骤。progress.yaml 的 resources 是资源台账唯一登记处。
计划体量
- 改动要点 + 关键 diff 片段 + 验收断言:改代码的步骤给出「要改什么、改成什么」——新增函数给完整函数体;修改既有代码给被改的行及前后 1-3 行锚点;文本类文件给「旧文本 → 新文本」对照;再给一条可运行的断言或测试。
- 禁止整文件内嵌:不把目标文件的现行内容或改后全文抄进任务,执行者自行 Read 现行文件。片段与目标文件现行内容逐字重合超过 30 行即视为整文件内嵌。
- 单任务文件上限 200 行:
tasks/TNN.md超过 200 行先拆任务,仍超则把片段收敛为要点;validate-output.mjs plan-index对超限文件报错expected: "<= 200 lines"。 - 体量参照:全部
tasks/*.md行数之和以不超过预期代码改动行数为目标,超出时在 index「体量说明」写一句原因。
禁止占位符
每一步必须包含工程师需要的实际内容。以下是计划失败,绝不允许出现:
- "TBD"、"TODO"、"稍后实现"、"补充细节"
- "添加适当的错误处理" / "添加校验" / "处理边缘情况"
- "为上述代码写测试"(没有实际测试代码)
- "类似任务 N"(把该任务自己的片段写出来——工程师可能乱序阅读任务)
- 只说做什么不给怎么做的步骤(涉及代码的步骤必须有片段或新旧对照)
- 引用任何任务中都未定义的类型、函数、方法
牢记
- 永远给精确文件路径
- 每步给关键片段——改代码的步骤必须展示新旧对照或新增代码,不抄整文件
- 精确命令 + 预期输出
- DRY、YAGNI、TDD、频繁提交
- 任务步骤会创建持久资源(容器、测试库/表、临时目录、后台服务)时,写计划时就在 progress.yaml 的初始
resources键预登记对应行——资源不允许只活在对话里
执行交接
保存计划后按 计划自检 完成适用的任务图语义审查,再展示最新 index 链接与简短变更摘要,列 2–3 个针对粒度、依赖或边界的陈述式检查点;有并发准备时交代扣除共享写入和资源冲突后的实际并发窗口,再作一次整体确认。检查点不附“请确认”“是否接受”等问题;确有未决点则先按一次一题澄清。保存、校验和提交状态以实际工具回执为准,稿件审阅认可不等于开始实施授权。向用户交接:
「计划已完成并保存至
.spec-dev/<特性目录>/plan/(index.md + tasks/ + progress.yaml)。执行时我会用 executing-plans 从任务 0(隔离工作区)开始,默认按依赖图派发就绪任务:可独立的并发,受依赖或资源约束的顺序推进,保留 TDD、每任务提交与收尾审查。现在开始执行,还是先 review 计划?」
本计划属于某 active roadmap 的子项目时,话术首句追加进度锚点「(roadmap <project> 第 N/M 个子项目)」——让用户在交接时刻看到全局位置。
交接列出共同前置、可重叠的任务链和资源限制,说明默认按图并发;仅确认「开始执行 / 先 review」,不另设串行/并发选择门。用户明确要求串行时沿用并记录该偏好;已有执行授权不重复询问。开始后统一交给 executing-plans——未回复、或只给了计划修改意见时不得启动执行;用户要改计划则修订后重跑 Self-Review。
Red Flags
- 步骤里出现"适当的""必要的""类似的" → 写出具体内容
- "spec 有三个阶段,那我写三份计划" → 一次只写一份:后续阶段的计划建立在尚不存在的代码上,写了必失效;剩余范围登记 roadmap
- 计划缺任务 0、独立 final 验证票或最终任务(合并与清理) → 按固定模板补上
- 普通行为票使用 TDD 五步;T00、纯重构、组验证和最终任务按自身类型保留完整步骤,不以超过五步自动拆票。独立交付物与必要依赖决定粒度。
- 测试步骤没有测试代码 → 补全
- 计划里没有一处精确文件路径 → 重写
- 想跳过 Self-Review 直接交接 → 五查跑完再交