语言协议:以对话语言输出——用户显式指定(含平台
language设置)优先,其次跟随用户近期消息语言;均无法判定时默认英语。落盘产物以创建时对话语言为准,增量修改保持产物既有语言。本 skill 中的固定话术是语义模板,用对话语言表达其意,不逐字照搬。
插件根:
${CLAUDE_PLUGIN_ROOT}——本 skill 正文与其 references 中的插件根命令以此为准;若上式仍为变量字面量(平台未替换),按 requirement-analysis 的 references/exploration-patterns.md「插件根解析」序列推导。
外部搜索统一入口:需要联网检索(资料、库/框架文档、时效信息)时一律先用 anysearch skill(插件内嵌),不可用再降级 WebSearch/WebFetch;降级链与派发词要求见 requirement-analysis 的 references/exploration-patterns.md。
编写实施计划
概述
假设执行计划的工程师对我们的代码库零上下文、且品味存疑:技术过硬,但几乎不了解我们的工具链和问题域,也未必懂好的测试设计。把他们需要知道的一切写进计划——每个任务动哪些文件、完整代码、怎么测试、参考哪些文档。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——被延后的范围必须有落盘登记,不允许只活在对话里
不变式:一次只写一份计划,不为未实施的后续阶段预写计划。计划要求每步含完整代码与精确路径,后续阶段的代码建立在前一阶段尚不存在的产物上——现在写出来必然失效。后续子项目在前置交付后按 roadmap 续接(executing-plans 收尾会核对 roadmap 并提示下一个)。
任务分解与方案形态遵循 design-principles.md 八条设计原则——分解时逐条对照,违反即重划。
文件结构先行
定义任务前,先画出将创建/修改的文件清单及各自职责——分解决策在这里锁定:
- 单元边界清晰、接口明确,每个文件一个职责
- 你对能一次装进上下文的代码推理得最好,文件聚焦时编辑也更可靠——偏向小而聚焦的文件
- 一起变化的代码放在一起:按职责拆分,不按技术分层拆分
- 既有代码库跟随既有模式;正在改的文件已经臃肿时,把拆分纳入计划是合理的,但不做无关重构
该结构决定任务分解:每个任务产出自包含、独立可理解的变更。
任务的粒度
任务是携带独立测试周期、值得一次独立审查的最小单元。划界时:把配置、脚手架、文档步骤折叠进需要它们的任务;只在"审查者可能拒绝一个任务而通过相邻任务"处切分。每个任务以一个可独立验证的交付物收尾。
步骤是一个动作(2-5 分钟):
- 「写失败测试」——一步
- 「运行确认失败」——一步
- 「写最小实现」——一步
- 「运行确认通过」——一步
- 「提交」——一步
TDD 循环的完整纪律遵循 test-driven-development skill——计划里的每个任务显式内嵌上述五步。
Scenario 直译为测试:spec 行为规范里的每个 #### 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 # 唯一运行时状态
可选并发声明
index 头部增加至多一个标记为 yaml spec-dev-parallel 的 fenced block;不存在表示无并发声明。其结构为 parallel: { tasks: { TNN: { writes: [路径], resources: [排他资源键] } } }。只声明可派给 implementer 且写集合非空的票,已知 TDD 例外或显式空基线范围的票不列入;未声明票由主线程串行执行且执行时排空 implementer。writing-plans 从任务文件块产生声明并在 Self-Review 核对同义一致;入口校验不预读 tasks 正文,implementer 读取自己任务后再核对文件块,任何差异阻塞该票。执行中才发现已授权例外时,子代理先回报 blocked,由主线程按 executing-plans-parallel 的例外票串行规则接管,不能伪造 ready 的测试证据。
写路径为精确文件名,不支持 glob/目录授权;使用 /、仓库根相对,拒绝空值、绝对路径、..、重复规范路径、大小写/Unicode 规范化碰撞;不存在的新文件按最近存在祖先解析符号链接。.git、.spec-dev(含所有计划/状态/证据)及其符号链接别名禁止进入 implementer 写集合。不同票的同一路径或祖先文件路径冲突不能同批;“不同文件读写形成语义依赖”必须在导航表声明依赖,路径不相交不证明接口独立。
resources 是该票使用的排他外部资源键(如数据库、端口、输出目录);同键不能同批。主线程用 claim 命名空间分配可隔离资源,不能把同一实体换名伪装隔离;无法确认隔离范围的票不加入并发声明。资源实际标识/清理命令只记 progress.resources。
plan-index 继续输出现有 {ok,schema,file,errors} 契约;新声明存在时校验其结构和合法路径,写集合重叠表示调度冲突而非整份计划非法。不新增额外计划文件或解析全部 YAML 特性:读取仓库当前支持的受限映射/数组形制,拒绝重复键和不支持的语法,不默默截断。
parallel:
tasks:
T01:
writes:
- "src/a.mjs"
- "tests/a.test.mjs"
resources: []
T02:
writes:
- "src/b.mjs"
- "tests/b.test.mjs"
resources:
- "port:claim-scoped-b"
受支持语法:根 parallel:、两空格 tasks:、四空格任务键、六空格 writes:/resources:、八空格 - "JSON 字符串";空数组写作 resources: []。不支持 YAML anchor、tag、折叠字符串、注释或 flow mapping;不在此块内使用其他缩进。writes 非空,resources 可空;不允许重复任务、字段、规范路径或资源键。
Self-Review 的 spec 覆盖与类型一致性两查同时核对声明与任务文件块一致、依赖覆盖语义耦合、已授权例外与空基线票已排除;该检查由计划作者本地执行,不派子代理自审计划。
计划文档头部
每份计划必须以此头部开始:
# [功能名] 实施计划
> **执行方式**:使用 spec-dev 的 executing-plans skill 逐任务执行本计划;无该 skill 的环境直接从任务 0 起按序执行至最终任务。任务状态由 `plan/progress.yaml` 跟踪(唯一状态源;任务文件步骤用「**步骤 N:**」标题式、不含复选框);脱离项目携带时连同特性目录(含 spec)整体带走。
>
> **偏差处理**:执行中发现计划与现实不符——小偏差(路径笔误、明显遗漏但意图清楚)就地修正并在提交信息中注明;接口、数据结构等契约级偏差停下向计划作者确认,不猜着改。
**目标**:[一句话说明构建什么]
**Spec**:[对应 spec 文件路径]
**架构**:[2-3 句方案概述]
**技术栈**:[关键技术/库]
**设计原则**:本计划遵循 spec-dev 设计原则(不留向后兼容垫片 / 最简实现 / 分层构建 / 不以未完成复杂性换可工作产品 / 模块化 / 优先成熟库 / 优先已有依赖 / 长期架构决策);任务与代码不得违反,冲突时停下向计划作者确认。
## 全局约束
[spec 的项目级要求——版本下限、依赖限制、命名与文案规则、平台要求——
每条一行,数值从 spec 逐字复制。每个任务的要求都隐含本节。]
## 相关测试范围
[写计划时推导的本特性相关测试执行声明——命令级、随计划被审、可改。推导优先级:
1) 项目已有测试影响分析工具 → 写具体命令(如 `nx affected -t test`、`jest --changedSince`、
`pytest --testmon`)。工具存在性以项目依赖/配置清单判定(package.json scripts、nx.json、
pytest 插件等),拿不准时询问用户;
2) 无工具 → 按 spec `covers` 与影响面推导测试文件/目录清单(路径判定,不做依赖分析)。
纯文档特性(`covers` 为空数组或全为文档路径)→ 显式声明为空并注明原因。
本声明约束任务 0 基线验证;最终任务的全量验证不受本节约束(全量安全网)。]
---
index.md 头部之后是任务导航表——四列:任务 | 依赖 | 消费接口 | 产出接口。规则:任务 ID 形如 T\d\d 全局唯一且与 tasks/ 文件名一一对应;依赖只引用表内 ID,可用闭区间写法(T01-T06 表示 T01 至 T06 闭区间——区间内每个编号都必须是表内任务,起点不得大于终点);禁止环;接口列写精确签名(执行者只读自己的任务文件 + 依赖行的产出接口,不读其它任务正文)。生成后运行 node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-output.mjs" plan-index <plan目录>(结构校验:文件↔导航表一致、依赖存在且区间可展开、无环),失败不得交付执行。
测试落点的接口传递
spec 测试策略中的获批 seam 沿四列导航的消费/产出接口及本票接口块传递:保留精确签名/协议,列出覆盖 Scenario、依赖替换边界和 spec 来源指针;执行者只读本票、spec 与依赖接口行就能获得同一边界,不把声明藏在前置任务正文。产出接口不是逐函数直测清单;不新增导航列、清单文件或 progress 字段。
静态快检命令
计划头部与本票测试命令中提供项目已有、适用的 typecheck/静态命令及配置来源,无则写不适用。编辑批次间快检的节奏与边界遵循 test-strategy;保留任务五步的有效红绿、相关测试、最终全量和失败归属裁决,不把编译报错写为预期红。
任务 0:建立隔离工作区(每份计划固定生成)
导航表首行为任务 0,固定生成 tasks/T00.md——与结尾的最终任务(合并与清理)首尾对称,隔离工作区的生命周期在计划目录内闭合、脱离本插件也能按序执行;有 using-git-worktrees skill 或原生工具的环境按其完整纪律执行(已隔离检测、目录选择、沙箱降级都定义在该 skill):
### 任务 0:建立隔离工作区
**步骤 1:检测已有隔离**
运行:`git rev-parse --git-dir` 与 `git rev-parse --git-common-dir`
两者不同、且 `git rev-parse --show-superproject-working-tree` 无输出(排除 submodule)
→ 已在隔离工作区,跳过本任务。
**步骤 2:建立 worktree**
有原生 worktree 工具(如 EnterWorktree)或 using-git-worktrees skill 时优先使用(Codex 无原生 worktree 工具,直接走下面的手工路径);否则手工降级:
确认 `.worktrees/` 已被忽略(`git check-ignore -q .worktrees`,未忽略先加入 `.gitignore` 并提交),然后
`git worktree add .worktrees/<分支名> -b <分支名>` 并切换到该目录(分支名对齐计划,如 `plan/YYYY-MM-DD-NN-<feature>`)。
**步骤 3:安装依赖并验证基线**
按项目类型安装依赖(npm install / cargo build / pip install -r requirements.txt / go mod download),
然后按计划头部「相关测试范围」运行基线验证:有声明 → 只跑声明范围(声明为空 → 跳过测试并注明,
最终任务全量验证照跑;声明命令执行报错或工具不可用 → 回退运行完整测试套件,并注明声明已失效、
建议修订计划);计划无该节(旧版计划)→ 运行完整测试套件,行为与现状一致。
基线测试失败 → 停下报告,先问再继续。
降级:非 git 仓库、或沙箱拒绝创建 → 在执行记录中注明"未隔离"及原因,原地继续任务 1。
任务结构
### 任务 N:[组件名]
**文件**:
- 创建:`exact/path/to/file.py`
- 修改:`exact/path/to/existing.py:123-145`
- 测试:`tests/exact/path/to/test.py`
**接口**:
- 消费:[本任务使用的前序任务产物——精确签名]
- 产出:[后续任务将依赖的——精确函数名、参数与返回类型。
任务执行者只看得到自己的任务;此块是他们了解相邻任务所用名称与类型的唯一途径。]
**步骤 1:写失败测试**
```python
def test_specific_behavior():
result = function(input)
assert result == expected
```
**步骤 2:运行测试确认失败**
运行:`pytest tests/path/test.py::test_name -v`
预期:FAIL,报 "function not defined"
**步骤 3:写最小实现**
```python
def function(input):
return expected
```
**步骤 4:运行测试确认通过**
运行:`pytest tests/path/test.py::test_name -v`
预期:PASS
**步骤 5:提交**
```bash
git add tests/path/test.py src/path/file.py
git commit -m "feat(TN): add specific feature"
```
progress.yaml 键结构
format_version: 1
current: T03 # 当前指针(null=未开始)
tasks:
T01: { status: completed, commit: <sha>, tests: pass }
T02: { status: completed, commit: <sha>, tests: pass, deviations: ["路径笔误就地修正"] }
T03: { status: in_progress }
resources: # 资源台账(唯一登记处;最终任务清理步骤遍历此清单)
- "worktree: .worktrees/<分支> —— git worktree remove …"
notes: [] # 偏差与备注,append-only
状态枚举:pending | in_progress | completed | blocked。写入纪律:每任务完成后原子更新(整文件重写)并随任务提交;worktree 合并不携带本文件冲突——它是执行档案,最终任务把它随特性目录归档。resources 键即资源台账规范定义点(生成时预登记 worktree 行、执行中创建即追加;最终任务清理遍历此清单)。
并发运行扩展(字段唯一定义点)
保留 format_version: 1、四种任务 status、resources、notes;增加可选 execution,其 mode: parallel 为并发语义的明确判别项。未出现该项的存量 progress 原样串行读取。current 只指主线程正在执行的串行票;并发派发期间为 null,不用它推断所有任务空闲,活动票以 tasks 中 in_progress 的认领为准。
execution 字段:mode、owner(会话唯一标识)、integration_worktree(绝对路径)、integration_branch、base_commit(特性审查基线)、validated_commit(最后通过集成验证的 tip)。可选 delivery:channel: local|pr、state: implementing|awaiting_merge|merged|completed、source_branch、pr_url、merge_commit;记录事实变化,不以 state 自证合并。
中途升级时增加可选 execution.activation: { from: serial, request_id: <切换请求唯一标识>, checkpoint_commit: <H>, authorization_ref: <已保存请求 notes 的定位> };H 是切换前已保存串行完成状态的提交,不是包含 activation 的提交。notes 以现有 append-only 字符串项保存 parallel-switch/<request_id>: requested; authorization=<原话或可恢复引用>,成功切换时追加同 ID 的 activated 事件;不另建待办状态文件,实际模式仍以已提交 execution 为准。初始就选择并发不要求该 activation 字段。用户的切换授权和任务声明是两个独立条件,声明存在不能代替授权。
tasks.TNN 继承 status/commit/tests/deviations,增加 claim: { key, owner, agent_id, worktree, branch, base_commit }、implementation_commit、result_path。claim.owner 表示最初认领的编排会话,execution.owner 表示当前持锁编排者;恢复接管可以更新后者,身份与通信已核验的存活 implementer 保留原 claim,不因主线程换会话而换 key。agent_id 在工具返回后补写;派发前 claim 已持久化,若在派发与补写之间崩溃则核对运行中 agent 与 worktree,不盲重派。completed 的 commit 是通过集成验证的提交,不能填包含该 SHA 字段的状态提交;实现提交和进度 checkpoint 分开,后者随特性分支保存。每次新尝试以新 key 替换 claim,旧 key 与处置原因追加 notes,历史结果文件保留。progress 使用临时文件+rename 原子更新,不允许子代理副本合并回来。
模型声明沿现有 notes 保存 model-declaration/<declaration_id>: <角色/任务组、模型、思考强度、来源、继承或计划派发标识>,不另造执行配置文件;新认领增加 claim.model_declaration_id 指向适用于该票的声明。先向用户展示;主线程取得对应进度写权限后,在首次相关派发前将声明及引用持久化。该记录用于追溯而非驱动模型选择,不能覆盖真实工具参数。旧认领没有该字段时,恢复从可用的原派发参数/会话记录核对,无法核实的部分标未知,不能把新主线程配置回填成原执行者事实。
未开始的计划不伪造 owner、模型声明、claim 或运行 SHA;生成时只预登记已知资源。并发 skill 在取得独占写权后填入真实值。资源只有主线程可以写入 progress,子代理新建持久资源必须先请求、主线程原子预登记并确认、最后创建;没有确认则资源操作阻塞。
验收任务(矩阵含「验收任务」行时固定生成)
spec 验收矩阵(「测试与验收策略」节)中执行方式为「任务内 TDD」的行直接翻译进各任务的失败测试步骤;执行方式为「验收任务」的行则在所有实施任务之后、最终任务(合并与清理)之前生成一个验收任务承载(编号顺延:最后实施任务为 N 则验收任务为 N+1、最终任务为 N+2):
### 任务 N+1:验收(acceptance-qa)
> 本任务由 executing-plans 收尾审查阶段触发 acceptance-qa 按下表执行,
> 不参与逐任务连续执行;报告与证据落盘特性目录 `acceptance/` 子目录。
| Scenario / 检查项 | 维度 | 执行方式 | 目标 | 阈值/预期 | 验收证据 |
|-------------------|------|---------|------|----------|---------|
| [从 spec 矩阵逐行抄录「验收任务」行,补全目标 URL/端点与阈值数字] | | | | | |
矩阵全部为「任务内 TDD」行、或 spec 无验收矩阵(旧版 spec)时不生成本任务;旧版 spec 的 UI 功能沿用在任务验收步骤注明「由 executing-plans 收尾触发 acceptance-qa 验收」并写明验收点(页面、交互、预期状态)。
最终任务:合并与清理(每份计划固定生成)
所有实施任务与验收任务(如有)之后,固定以下述任务收尾(编号顺延全局任务号:有验收任务时为 N+2、无则为 N+1,下方模板以 N+2 示意)——与任务 0 首尾对称,worktree 从建立到合并的生命周期在计划目录内闭合。使用 executing-plans 编排执行时,本任务不参与阶段 3 连续执行,推迟到收尾审查处置完成后运行:
### 任务 N+2:合并与清理
**资源台账**(承载于 `plan/progress.yaml` 的 `resources` 键——规范定义点见「progress.yaml 键结构」节;行格式 `<类型>: <标识> —— <清理命令>`);下方清理步骤遍历该清单。
progress.yaml 已预登记首行(示意):`worktree: .worktrees/<分支名> —— git worktree remove .worktrees/<分支名> && git branch -d <分支名>`
台账总则:**清理只遍历本台账、台账外一律不动**(可疑残留只报告不删);共享缓存(~/.cargo、pnpm store、npm cache 等)默认保留,仅用户显式要求清理时才登记入账;台账限定持久资源(容器、测试库/表、临时目录、后台服务),worktree 内构建产物随 worktree 删除自然回收、不入账。
**步骤 1:全量验证(安全网)与归属裁决**
在 worktree 内运行完整测试套件(不受「相关测试范围」约束)。
- 全绿 → 进入步骤 2。
- 失败测试在相关测试范围内(或计划无该节)→ 修复并复跑全绿后进入步骤 2。
- 失败测试在范围之外 → 归属裁决:在主工作区的源分支检出上复跑该测试
(主工作区有未提交改动 → 先询问用户)。源分支同样失败 → 报告"既有失败",
请用户裁决是否阻塞合并,不自行静默忽略;源分支通过 → 判定为本次引入的回归,
修复并复跑全绿后进入步骤 2。
**步骤 2:测试退役检查**
扫描路径落在本计划「相关测试范围」内的测试,找孤儿测试:测试名对不上任何 active spec
的**现行** Scenario(现行=所在 Requirement 未被 `Superseded` 标注;判定基础是本 skill
"测试名沿用 Scenario 名"约定,不合该命名约定的历史测试不进候选,保守豁免),且对应
Requirement 已 REMOVED、**或其标题下带 `Superseded` 标注**、或所属 spec 已 superseded——
双条件缺一不可。候选清单非空 → 列清单征询用户,同意后删除并计入本任务提交;用户未确认则不删除
任何测试。无候选 → 声明"无孤儿测试"后跳过。计划无「相关测试范围」节 → 跳过本步骤。
**步骤 3:取代回写(spec 的 `supersedes` 为空——字段缺失或空数组——时声明"无取代回写"后跳过)**
按 spec「取代与共存」节逐项执行(形制见 spec-template「取代标注形制」节;实施任务中已完成的回写在此逐项核对):
- 完全取代:旧 spec frontmatter `status` 翻 `superseded`、`superseded_by` 填本 spec 仓库根路径;H1 下 `Superseded-pending` 行替换为 `Superseded` 行;此后该 spec 的 sync_commit 冻结。
- 部分取代:旧 spec 保持 active,每条被取代 `### Requirement:` 标题下插入 Superseded 标注行;H1 下 pending 行移除;同步「取代与共存」节要求的关联文本(判据、术语表等)。
- covers 接管核对(仅完全取代):列出旧 spec covers 中不被本 spec covers 覆盖且仍存在的路径差集;差集非空 → 停下征询用户(补进本 spec covers / 确认放弃保护并记录),不静默翻转。
- 回写随本分支合并进主线生效,与步骤 6 的 sync_commit 锚定构成取代提交组(revert 该组即原子恢复)。
**步骤 4:合并回来源分支**
```bash
cd "$(dirname "$(git rev-parse --git-common-dir)")" # 回到主工作区
git merge <分支名> # 任务 0 创建的分支
```
合并冲突、或主工作区有未提交改动 → 停下向计划作者确认,不强行合并。
**步骤 5:清理(按资源台账逐条执行)**
逐条执行 progress.yaml resources 清单各行的清理命令(worktree 行即清单首行)。命令执行失败 → 该行保留在清单中并报告用户,不静默跳过;资源已不存在 → 从清单移除并在 notes 记一行"已不存在"。台账外的文件、容器、数据一律不动。
**步骤 6:sync_commit 锚定**
```bash
SYNC=$(git rev-parse HEAD) # 合并完成后的主工作区 HEAD
# 把 spec frontmatter 的 sync_commit: null(或旧值)更新为 $SYNC
git add <spec 路径> && git commit -m "chore(spec): sync_commit 锚定 ${SYNC:0:7}"
```
此后 `git diff <sync_commit>..HEAD -- <covers glob>` 即"spec 上次确认同步以来的代码变化"。非 git 仓库跳过。
任务 0 未由本计划建立 worktree(此前已在隔离环境、原生工具建立、或降级原地执行)→ 只执行步骤 1、2、3 与步骤 6,步骤 4-5 交回原有隔离机制收尾并注明。计划无对应 spec(无 spec 输入的独立触发)→ 生成本任务时省略步骤 3 与步骤 6,或在执行记录注明"无 spec,跳过取代回写与锚定"。
禁止占位符
每一步必须包含工程师需要的实际内容。以下是计划失败,绝不允许出现:
- "TBD"、"TODO"、"稍后实现"、"补充细节"
- "添加适当的错误处理" / "添加校验" / "处理边缘情况"
- "为上述代码写测试"(没有实际测试代码)
- "类似任务 N"(把代码重复写出来——工程师可能乱序阅读任务)
- 只说做什么不给怎么做的步骤(涉及代码的步骤必须有代码块)
- 引用任何任务中都未定义的类型、函数、方法
牢记
- 永远给精确文件路径
- 每步给完整代码——改代码的步骤必须展示代码
- 精确命令 + 预期输出
- DRY、YAGNI、TDD、频繁提交
- 任务步骤会创建持久资源(容器、测试库/表、临时目录、后台服务)时,写计划时就在 progress.yaml 的初始
resources键预登记对应行——资源不允许只活在对话里
Self-Review
写完整份计划后,以新鲜眼光对照 spec 检查(自己跑清单,不派子代理):
- Spec 覆盖:逐条 Requirement 过——能指到实现它的任务吗?每个 Scenario 都有对应的失败测试步骤吗(GIVEN/WHEN/THEN → arrange/act/assert)?验收矩阵的「验收任务」行都进入验收任务表了吗?差量三节的 MODIFIED/REMOVED 有对应的改造/清理任务吗?列出缺口
- 占位符扫描:按"禁止占位符"清单搜索计划全文,发现即修
- 类型一致性:后续任务用到的类型、方法签名、属性名与前序任务定义一致吗?任务 3 叫
clearLayers()、任务 7 叫clearFullLayers()就是 bug - 导航表与任务文件一致:导航表接口列与各任务文件的接口块逐条一致吗?tasks/ 文件名与表内任务 ID 一一对应吗(plan-index 校验过再交付)?
发现问题就地修复,无需复审;发现 spec 需求没有对应任务就补任务。
执行交接
保存计划后向用户交接:
「计划已完成并保存至
.spec-dev/<特性目录>/plan/(index.md + tasks/ + progress.yaml)。执行时我会用 executing-plans 从任务 0(隔离工作区)开始逐任务执行(TDD + 每任务提交 + 收尾多维审查)。现在开始执行,还是先 review 计划?」
本计划属于某 active roadmap 的子项目时,话术首句追加进度锚点「(roadmap <project> 第 N/M 个子项目)」——让用户在交接时刻看到全局位置。
用户明确选择「开始执行」后才调用 executing-plans skill——未回复、或只给了计划修改意见时不得启动执行;用户要改计划则修订后重跑 Self-Review。
Red Flags
- 步骤里出现"适当的""必要的""类似的" → 写出具体内容
- "spec 有三个阶段,那我写三份计划" → 一次只写一份:后续阶段的计划建立在尚不存在的代码上,写了必失效;剩余范围登记 roadmap
- 计划缺任务 0(隔离工作区)或最终任务(合并与清理) → 按固定模板补上
- 一个任务超过 5 个实施步骤 → 任务过大,继续拆
- 测试步骤没有测试代码 → 补全
- 计划里没有一处精确文件路径 → 重写
- 想跳过 Self-Review 直接交接 → 四查跑完再交