Language Protocol / 语言协议: Respond in the user's conversation language — an explicit user instruction (including the platform
languagesetting) takes precedence, then the language of the user's recent messages; default to English when neither indicates a language. All deliverables written to the repo (specs, plans, reports, notes) follow the conversation language at creation; incremental edits keep the artifact's existing language. Fixed-wording prompts in this skill are semantic templates — express their meaning in the conversation language, don't quote them verbatim. 语言协议:以对话语言输出——用户显式指定(含平台language设置)优先,其次跟随用户近期消息语言;均无法判定时默认英语。落盘产物以创建时对话语言为准,增量修改保持产物既有语言。本 skill 中的固定话术是语义模板,用对话语言表达其意,不逐字照搬。
编写实施计划
概述
假设执行计划的工程师对我们的代码库零上下文、且品味存疑:技术过硬,但几乎不了解我们的工具链和问题域,也未必懂好的测试设计。把他们需要知道的一切写进计划——每个任务动哪些文件、完整代码、怎么测试、参考哪些文档。DRY、YAGNI、TDD、频繁提交。
开始时声明:「我正在使用 writing-plans skill 编写实施计划。」
动笔前确认:编写计划须持有用户的明确同意——用户本轮显式指示编写计划、或上游流程已代为确认(requirement-analysis 阶段 8 的前置确认)时视为已同意、不重复问;除此之外(如隐式触发、只收到一个 spec 路径)先确认「基于 <spec 路径> 开始编写实施计划?」再动笔。
计划保存至:spec 所在特性目录的 plan/<feature-name>-plan.md(即 .spec-dev/YYYY-MM-DD-<feature-name>/plan/<feature-name>-plan.md,特性目录由 requirement-analysis 在写 spec 时创建);无 spec 输入的独立触发则自建特性目录。用户对计划位置的偏好优先于此默认值。
Spec 状态检查:载入 spec 时读其 frontmatter 的 spec_dev.status——仍为 draft 时说明漂移守卫尚未激活(requirement-analysis 阶段 8 的激活动作未执行,常见于跨会话独立触发):与用户确认 spec 已定稿后,把 status 翻为 active 并单独 commit,再开始编写计划;不翻转则守卫对该特性静默失效。无 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-<project>.md,无则新建:frontmatterspec_dev_roadmap(version/project/status: active)+ 子项目表(序号/名称/一句话范围/依赖/状态/特性目录),本子项目行记in-progress、剩余行记pending)并 git commit——被延后的范围必须有落盘登记,不允许只活在对话里
不变式:一次只写一份计划,不为未实施的后续阶段预写计划。计划要求每步含完整代码与精确路径,后续阶段的代码建立在前一阶段尚不存在的产物上——现在写出来必然失效。后续子项目在前置交付后按 roadmap 续接(executing-plans 收尾会核对 roadmap 并提示下一个)。
文件结构先行
定义任务前,先画出将创建/修改的文件清单及各自职责——分解决策在这里锁定:
- 单元边界清晰、接口明确,每个文件一个职责
- 你对能一次装进上下文的代码推理得最好,文件聚焦时编辑也更可靠——偏向小而聚焦的文件
- 一起变化的代码放在一起:按职责拆分,不按技术分层拆分
- 既有代码库跟随既有模式;正在改的文件已经臃肿时,把拆分纳入计划是合理的,但不做无关重构
该结构决定任务分解:每个任务产出自包含、独立可理解的变更。
任务的粒度
任务是携带独立测试周期、值得一次独立审查的最小单元。划界时:把配置、脚手架、文档步骤折叠进需要它们的任务;只在"审查者可能拒绝一个任务而通过相邻任务"处切分。每个任务以一个可独立验证的交付物收尾。
步骤是一个动作(2-5 分钟):
- 「写失败测试」——一步
- 「运行确认失败」——一步
- 「写最小实现」——一步
- 「运行确认通过」——一步
- 「提交」——一步
TDD 循环的完整纪律遵循 test-driven-development skill——计划里的每个任务显式内嵌上述五步。
Scenario 直译为测试:spec 行为规范里的每个 #### Scenario: 至少翻译成一个失败测试,映射固定:GIVEN→arrange(构造前置状态)、WHEN→act(触发动作)、THEN→assert(断言可观察结果);测试名沿用 Scenario 名。规范到测试零翻译损耗——不要自己另编测试场景后把 Scenario 丢在一边。
大型计划的分组导航:任务数超过 6 个时,按工作域插入分组标题(如 ## 数据层、## 接口层、## 测试与验收)组织任务顺序;任务编号保持全局连续(任务 0..N)不受分组影响——commit 前缀 feat(TN)、勾选与接口块引用都以全局编号为准。分组同时暴露并行边界:不同组且无接口依赖的任务天然可并行。
计划文档头部
每份计划必须以此头部开始:
# [功能名] 实施计划
> **执行方式**:使用 spec-dev 的 executing-plans skill 逐任务执行本计划;无该 skill 的环境直接从任务 0 起按序执行至最终任务。步骤用复选框(`- [ ]`)语法跟踪;脱离项目携带时连同特性目录(含 spec)整体带走。
>
> **偏差处理**:执行中发现计划与现实不符——小偏差(路径笔误、明显遗漏但意图清楚)就地修正并在提交信息中注明;接口、数据结构等契约级偏差停下向计划作者确认,不猜着改。
**目标**:[一句话说明构建什么]
**Spec**:[对应 spec 文件路径]
**架构**:[2-3 句方案概述]
**技术栈**:[关键技术/库]
## 全局约束
[spec 的项目级要求——版本下限、依赖限制、命名与文案规则、平台要求——
每条一行,数值从 spec 逐字复制。每个任务的要求都隐含本节。]
---
任务 0:建立隔离工作区(每份计划固定生成)
头部之后、任务 1 之前,固定写入以下任务 0——与结尾的最终任务(合并与清理)首尾对称,隔离工作区的生命周期在计划文档内闭合、脱离本插件也能按序执行;有 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-<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"
```
验收任务(矩阵含「验收任务」行时固定生成)
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:合并与清理
- [ ] **步骤 1:全量验证**
在 worktree 内运行完整测试套件,确认全绿。失败 → 修复后才进入合并。
- [ ] **步骤 2:合并回来源分支**
```bash
cd "$(dirname "$(git rev-parse --git-common-dir)")" # 回到主工作区
git merge <分支名> # 任务 0 创建的分支
```
合并冲突、或主工作区有未提交改动 → 停下向计划作者确认,不强行合并。
- [ ] **步骤 3:清理**
```bash
git worktree remove .worktrees/<分支名>
git branch -d <分支名>
```
- [ ] **步骤 4: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 与步骤 4,步骤 2-3 交回原有隔离机制收尾并注明。计划无对应 spec(无 spec 输入的独立触发)→ 生成本任务时省略步骤 4,或在执行记录注明"无 spec,跳过锚定"。
禁止占位符
每一步必须包含工程师需要的实际内容。以下是计划失败,绝不允许出现:
- "TBD"、"TODO"、"稍后实现"、"补充细节"
- "添加适当的错误处理" / "添加校验" / "处理边缘情况"
- "为上述代码写测试"(没有实际测试代码)
- "类似任务 N"(把代码重复写出来——工程师可能乱序阅读任务)
- 只说做什么不给怎么做的步骤(涉及代码的步骤必须有代码块)
- 引用任何任务中都未定义的类型、函数、方法
牢记
- 永远给精确文件路径
- 每步给完整代码——改代码的步骤必须展示代码
- 精确命令 + 预期输出
- DRY、YAGNI、TDD、频繁提交
Self-Review
写完整份计划后,以新鲜眼光对照 spec 检查(自己跑清单,不派子代理):
- Spec 覆盖:逐条 Requirement 过——能指到实现它的任务吗?每个 Scenario 都有对应的失败测试步骤吗(GIVEN/WHEN/THEN → arrange/act/assert)?验收矩阵的「验收任务」行都进入验收任务表了吗?差量三节的 MODIFIED/REMOVED 有对应的改造/清理任务吗?列出缺口
- 占位符扫描:按"禁止占位符"清单搜索计划全文,发现即修
- 类型一致性:后续任务用到的类型、方法签名、属性名与前序任务定义一致吗?任务 3 叫
clearLayers()、任务 7 叫clearFullLayers()就是 bug
发现问题就地修复,无需复审;发现 spec 需求没有对应任务就补任务。
执行交接
保存计划后向用户交接:
「计划已完成并保存至
.spec-dev/<特性目录>/plan/<feature>-plan.md。执行时我会用 executing-plans 从任务 0(隔离工作区)开始逐任务执行(TDD + 每任务提交 + 收尾多维审查)。现在开始执行,还是先 review 计划?」
本计划属于某 active roadmap 的子项目时,话术首句追加进度锚点「(roadmap <project> 第 N/M 个子项目)」——让用户在交接时刻看到全局位置。
用户明确选择「开始执行」后才调用 executing-plans skill——未回复、或只给了计划修改意见时不得启动执行;用户要改计划则修订后重跑 Self-Review。
Red Flags
- 步骤里出现"适当的""必要的""类似的" → 写出具体内容
- "spec 有三个阶段,那我写三份计划" → 一次只写一份:后续阶段的计划建立在尚不存在的代码上,写了必失效;剩余范围登记 roadmap
- 计划缺任务 0(隔离工作区)或最终任务(合并与清理) → 按固定模板补上
- 一个任务超过 5 个实施步骤 → 任务过大,继续拆
- 测试步骤没有测试代码 → 补全
- 计划里没有一处精确文件路径 → 重写
- 想跳过 Self-Review 直接交接 → 三查跑完再交