mcpField
W
write-plan

write-plan

github.com/existential-birds开发8550 次安装12 周前更新
代码仓库

关于 write-plan

write-plan 将已批准的 brainstorm-beagle 规格文档转为面向工程师或下游 Agent 的逐任务实现计划。它先梳理文件和项目约定,再拆分为小型测试驱动任务;不会执行计划或修改生产代码。

主要功能

  1. 01要求提供 brainstorm-beagle 规格文档
  2. 02检查项目约定及相关代码
  3. 03编写任务前规划文件结构
  4. 04拆分为 TDD 步骤
  5. 05为未经验证的假设安排 spike
  6. 06依据规格文档审核计划

适用场景

  1. 01根据已批准的规格准备执行计划
  2. 02规划需遵循仓库约定的工作
  3. 03找出需要通过 spike 验证的工具行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill write-plan

安装后在 Claude Code 中输入/write-plan确认已加载。

附带文件references/plan-reviewer.mdreferences/plan-template.md

详细介绍

编写计划:将规范转化为实施计划

将 brainstorm-beagle 规范转化为全面的实施计划,让工程师(或下游 Agent)无需重新推导意图,就能逐项执行任务。

输出是一份 Markdown 计划文档,保存于 .beagle/concepts/<slug>/plan.md,与规范位于同一概念文件夹中。计划说明 HOW——文件结构、任务拆分、准确代码和准确命令;WHAT 和 WHY 已由规范明确。

<hard_gate> 在 .beagle/concepts/<slug>/spec.md 中存在 brainstorm-beagle 规范之前,切勿开始编写计划。如果缺少规范,请停止并先引导用户使用 brainstorm-beagle。跳过规范会导致计划建立在未经审视的假设之上——规范是本技能据以制定计划的契约。 </hard_gate>

工作流程

按顺序完成以下步骤:

  1. 定位规范 — 找到 .beagle/concepts/<slug>/spec.md;如果不存在,请停止并引导用户使用 brainstorm-beagle
  2. 阅读规范 — 阅读所有章节;不要改述,也不要在总结时省略要求
  3. 阅读项目约定 — 查看项目约定(例如根目录和嵌套目录中的 AGENTS.md 或 CLAUDE.md),了解计划必须遵守的测试、注释和架构规则
  4. 探索相关代码 — 阅读计划将涉及或作为模式参考的现有文件;不要猜测结构
  5. 设计文件结构 — 在编写任何任务之前,明确将创建或修改哪些文件
  6. 拆分任务 — 每项任务都应小而具体(2–5 分钟的步骤),遵循 TDD,并包含准确路径和代码
  7. 自我审查 — 对照规范检查,扫描占位内容,验证类型一致性(见下文的 自我审查)
  8. 可选:执行审查 — 仅适用于篇幅较长或涉及不熟悉领域的计划。如果 Agent 支持子 Agent,则派发审查子 Agent;否则在当前上下文中执行同样的审查——输出完全相同(见 references/plan-reviewer.md)
  9. 向用户展示草稿 — 在聊天中展示草稿供用户审阅;如有需要,继续迭代
  10. 写入磁盘 — 仅在用户明确批准后,保存至 .beagle/concepts/<slug>/plan.md
Spec at .beagle/concepts/<slug>/spec.md? ── No  → STOP, route to brainstorm-beagle
                                          ── Yes → Read spec + project conventions + relevant code
                                                   ↓
                                                   Design file structure
                                                   ↓
                                                   Decompose into TDD tasks
                                                   ↓
                                                   Self-review → fix inline
                                                   ↓
                                                   (optional) Dispatch reviewer subagent
                                                   ↓
                                                   Present draft → User review
                                                                  ├─ Changes? → Revise
                                                                  └─ Approved? → Write to plan.md

最终状态是一份已写入的计划。 本技能不会执行计划、运行测试或修改生产代码。写入后,会询问是否生成执行交接提示词;如果用户同意,则在本次会话中加载 subagent-prompt 技能(../../../beagle-core/skills/subagent-prompt/SKILL.md)并生成提示词;否则告知用户计划已准备就绪。

定位规范

默认输入路径为 .beagle/concepts/<slug>/spec.md。

Slug 解析优先级(按顺序):

  1. 用户提供的路径或 slug(write-plan auth-rewrite、"plan the spec at .beagle/concepts/foo/spec.md")
  2. .beagle/concepts/ 下最近编辑的规范
  3. 存在多个可能的规范时,询问用户以确定目标

如果规范不存在:

"我找不到 .beagle/concepts/<slug>/spec.md 中的 brainstorm-beagle 规范。请先运行 brainstorm-beagle 生成规范,然后再回来制定计划。"

不要继续。规范是契约;没有规范就制定计划,相当于用另一个名称重新发明规范,并跳过 brainstorm-beagle 强制执行的审查关卡。

范围检查

如果规范涵盖多个相互独立的子系统,就应该在头脑风暴阶段拆分。如果没有拆分,请停下来并建议拆分——brainstorm-beagle 工作流包含一个范围评估步骤。每份计划都应为一个内聚的子系统产出可运行、可测试的软件。

以下迹象表明,规范过于宽泛,不适合放在一份文档中规划:

  • 必须满足的要求超过约 15 项,且没有共同的核心循环
  • 要求涉及相互独立的子系统(身份验证、计费、分析——各自都应有单独的计划)
  • 无法在 30 秒内解释核心循环

**行动:**向用户提出异议,并说明:“这份规范涵盖的不止一个内聚系统。我建议在 brainstorm-beagle 阶段拆分,并分别规划每份子规范。要这样做,还是继续制定一份大型计划?”

了解项目约定

设计任务前,先检查会影响计划的项目规则:

  • 仓库根目录以及你将修改的任何子目录中的项目约定(例如 AGENTS.md 或 CLAUDE.md)——测试级别、注释规范、提交约定、禁止的模式
  • 测试框架和运行器——Cargo、pytest、npm test、mix test 等。任务必须使用正确的命令。
  • 现有模式——如果代码库采用特定的文件布局,就应遵循。规范中的约束和参考点通常会明确这些要求。

如果项目约定文档要求某些具体事项(例如,“每项面向用户的功能都必须通过编译后的二进制程序进行第 3 级测试”),计划就必须包含满足该规则的任务。不要悄悄制定违反项目政策的计划——请指出问题并调整计划。

锁定计划前先做 Spike

仅依据文档编写计划,会导致对工具链的假设在首次接触代码库时就失效。锁定计划前,请找出所有这类说法:“工具 X 支持行为 Y”或“命令 Z 会生成输出 W”,但当前仓库或团队都没有可用示例加以验证。每一项都是一个Spike 候选项。

对于每个 Spike 候选项,计划必须包含一个 Task 0: Spike <claim>,其正文应当:

  1. 按照文档记录的步骤,在此仓库中运行计划其余部分所依赖的规范命令。
  2. 记录实际输出(包括成功路径和失败模式)。
  3. 二选一:确认规范中的关键决策仍然成立,或者在运行任何其他任务之前,将发现反馈给用户并提出具体的修订建议。

如果规范的关键决策依赖团队尚未在此仓库中验证过的工具行为,Task 0 就不可省略。以下是必须进行 Spike 的说法示例:

  • “工具 X 的 --workspace 标志可在一次调用中处理此仓库的多后端布局。”
  • “库 Y 的默认测试属性使用与生产环境相同的连接池配置。”
  • “CLI Z 的内省功能涵盖我们将编写的所有查询类型。”
  • “迁移框架 W 能在全新数据库上幂等地处理并发迁移器。”
  • **输入形状假设:**规范假设上游输入以 X 形状到达——完整/已排序/已去重/全部到齐/已通过验证——但尚无人验证此仓库中是否确实如此。(保留策略规范假设“工具输出是完整的”;但流式工具并非如此——新层看到输出前,滚动缓冲区已在上游淘汰了前缀。)关于上游数据形状的关键假设是 Spike 候选项,不是既定事实。

如果 Spike 失败或发现限制,请停下来修订规范——不要用额外的计划任务来掩盖这一发现。如果规范基于某个行为作出了关键决策,而该行为并未如预期运作,那么这份规范需要再次进行头脑风暴,而不是制定更多变通方案。

这条规则比现有的假设审查更严格。假设是“我在猜测尚未验证的行为”。Spike 候选项是“规范基于无人验证过的行为作出了关键决策”。前者需要记录;后者需要实际运行验证。

并行实现门槛

当计划为现有功能添加并行实现时(例如,在同一 trait 后接入第二种数据库后端、为同一 UI 添加第二个平台目标,或为同一服务添加第二种协议适配器),计划必须以一个最终任务收尾,且该任务正文必须包含:

  1. 找出用于固定现有实现可观察行为的规范契约/一致性测试套件。
  2. 在同一次调用中,对两种实现运行该套件。
  3. 断言可观察行为逐字节相同——返回值、持久化行、发出的事件、错误变体。内部结构体布局不算。
  4. 如果任一实现的契约测试未通过,则任务失败。只要套件中仍能看出差异,就不得宣布计划完成。

此任务是最终门槛,不可省略。没有它,“并行实现第二种后端”的计划就会交付存在差异的实现——执行者会各自独立地宣布每个后端的任务已完成,而能同时检查两者的契约测试却会在无人察觉的情况下继续失败。

行为等价性门槛独立于各任务的契约测试。各任务的测试固定单个实现的行为;该门槛则证明它们彼此一致。

文件结构

定义任务之前,先梳理将要创建或修改哪些文件,以及每个文件负责什么。此时应敲定拆分决策。

  • 设计边界清晰、接口明确的单元。每个文件都应有一个明确职责。
  • 你最擅长处理能一次纳入上下文的代码,文件越专注,修改就越可靠。优先选择更小、更专注的文件,避免大文件承担过多职责。
  • 应一起修改的文件应放在一起。按职责拆分,而不是按技术层拆分。
  • 在现有代码库中,遵循既有模式。如果代码库使用大文件,不要擅自重构;但如果你要修改的文件已经过于庞大,在计划中加入拆分也是合理的。

文件结构部分应出现在计划文档本身中,以便工程师(或下一个 Agent)在阅读具体任务前了解工作的大致结构。

适度拆分任务

每个步骤只做一项操作(2-5 分钟):

  • “编写失败测试”——一个步骤
  • “运行测试,确认其失败”——一个步骤
  • “编写最精简的代码,使测试通过”——一个步骤
  • “运行测试,确认其通过”——一个步骤
  • “提交”——一个步骤

把多项操作捆绑在一起的步骤(“编写测试和实现”)过于粗略——应拆分开。抽象描述行为的步骤(“添加验证”)过于含糊——应写明具体代码。

计划文档格式

使用 references/plan-template.md 中的模板。计划包含以下部分(按顺序):

  1. 标题栏——标题、目标、架构草图、技术栈、指回规格说明的链接
  2. 文件结构——要创建或修改的文件及其职责列表
  3. 任务 N 块——每个连贯的工作单元各一个,内部包含 TDD 步骤
  4. 自我审查结果——简短说明,确认自我审查过程诚实可信

每份计划都必须以此标题栏开头(使用原样的 Markdown,并填入方括号中的内容):

# [Feature Name] Implementation Plan

> **Source spec:** `.beagle/concepts/<slug>/spec.md`
> **For downstream agents:** Execute task-by-task. Each task uses `- [ ]` checkboxes for tracking. Do not skip the test-first steps — they catch wiring bugs that pure-logic tests miss.

**Goal:** [One sentence describing what this builds, mirroring the spec's Core Value]

**Architecture:** [2-3 sentences about approach — how the pieces fit together]

**Tech Stack:** [Key technologies/libraries this plan uses]

---
任务模板
### Task N: [Component Name]

**Files:**
- Create: `exact/path/to/file.ext`
- Modify: `exact/path/to/existing.ext:123-145`
- Test: `tests/exact/path/to/test.ext`

- [ ] **Step 1: Write the failing test**

```
// Show the assertions and the call site under test. The seed/setup
// loops are recovered by the executor from existing types and helpers
// — name a helper (e.g. `seed_entries(&store, id, count)`) but do not
// implement it here.
//
// Target: ~15 lines or less. Assertions pin observable consequence
// (a value, a file, a row, an output the next call would see), never
// dispatch ("the handler was called", "an event was emitted").
```

- [ ] **Step 2: Run test to verify it fails**

Run: `<exact project test command for this one test>`
Expected: FAIL — "<the exact failure message you expect>"

- [ ] **Step 3: Implement against the test**

**Files touched:** `path/to/impl.ext`

**Behavior contract** (what the implementation must satisfy — the executor writes the code):
- [The new/changed behavior bullet 1 — what's different from the reference]
- [The new/changed behavior bullet 2]
- [Up to 5 bullets total; past that, replace with a tighter reference]

**Reference:** `path/to/analog.ext:line-line` — [one-sentence delta: what to mirror, what to change]. Pointers only; do NOT paste the cited code inline. The executor opens the file.

- [ ] **Step 4: Run the new test AND the relevant suite, verify both green**

Run: `<same test command as Step 2>` → Expected: PASS.
Then run: `<the broader test scope this task lives in — the module, the package, the contract suite, whichever covers the surface this task touched>` → Expected: PASS with zero regressions.

A new test that passes while a sibling test silently turns red is a task failure, not a deferred concern. "I only ran the one I wrote" is how a contract test stays red across an entire plan. Specify the exact broader-scope command in this step; do not leave it as "run the suite" — the executor needs a copy-pasteable command.

- [ ] **Step 5: Sweep modified files for leftovers**

Describe sweep targets in plain language: "remove stale references to `<old_name>`, the orphaned `<import>`, and doc-comments describing the old shape." The executor greps for them. Do NOT enumerate line numbers in the plan — they will be wrong by execution time and the executor can find them faster than you can list them. New-file-only and config-only tasks skip this step.

- [ ] **Step 6: Commit**

```bash
git add <specific paths>
git commit -m "<type>(<scope>): <imperative summary>"
```

按步骤编写代码:测试要写,实现不要写

计划的职责是明确每项任务的契约。测试就是契约;实现则是执行者满足契约的方式。计划对二者的处理方式不同。

以下内容要展示真实、准确的代码:

  • 测试步骤主体——断言就是契约。如果测试断言了错误的内容,实现就算有误,测试套件也可能照样通过。因此,计划中的测试必须精确编写,使用项目的语言,以及测试实际会用到的函数和类型。
  • 命令——准确的测试命令、迁移命令、lint/类型检查命令。不能只用另一种说法概述。
  • 提交消息——准确的字符串。
  • 配置变更——配置文件的准确差异(依赖版本、功能标志、环境变量),其中的值就是契约。

以下内容不要展示完整代码:

  • 实现步骤主体。 规划者并不知道实际类型签名、实际库版本和执行者可以看到而规划者看不到的相邻代码,因此只能猜测即将编写的代码。计划中预先写好的实现,到了开始执行时几乎总会出错;执行者还得把实际代码与规划者的草稿协调起来,这比完全不写草稿更糟。

    对于实现步骤,应改为提供:

    • 修改的文件——准确路径
    • 行为契约——用 2–5 条要点说明实现必须满足什么。使用通俗语言。可根据前一步中的测试进行验证。
    • 参考——指向最接近的现有类似实现,或规范“参考点”中最接近的类比

这并不意味着可以含糊其辞。“行为契约”指的是测试会验证的具体、可观察行为。禁止使用“处理错误”之类的要点;必须明确写出:“如果输入包含重复 ID,则返回项目的错误类型所表示的 Err/异常,并在消息中指出重复的 ID”。

原则是:计划定义什么才算正确;执行者编写满足该定义的代码。 这正是 TDD 的理念;在计划中和执行时各写一次实现,颠倒了顺序。

凡是引入可失败操作的契约,都必须包含失败传播策略。 如果任务新增了序列化、反序列化、解析、类型转换、网络调用、文件打开或任何其他可能返回错误的操作,契约就必须说明错误如何传播:

  • 必需策略:对于边界内部的代码路径(即输入已经通过验证后运行的任何路径),通过项目的错误类型传播错误。使用 ?、change_context 或 map_err 转换为项目对应的变体,由调用方决定如何处理。
  • 禁止的模式:使用 .unwrap_or(<非默认回退字符串>),将 None 或 Err 强行转换成看似合理的占位值;对默认值有实际含义的类型(空字符串、零 ID、默认枚举变体)调用 .unwrap_or_default();静默调用 .ok() 丢弃错误。
  • 仅允许明示的例外:契约明确说明的情况才可例外,例如类型系统能明确表明的真实默认值(当规范规定结果为“没有结果”时使用空 vector),并用一句话说明该默认值为何正确。

“将 entry_type 序列化到行中”之类的要点并不充分;要点必须说明“通过 to_value 序列化;通过 .as_str().ok_or_else(...)? 强制转换为字符串;绝不静默替换为回退变体”。如果契约没有明确说明策略,执行者就会使用 unwrap_or,最终导致 Bug 上线。

可恢复性测试

每完成一个步骤的草稿,都要逐行重读并自问:

“执行者需要这一行吗?还是只要阅读引用的文件就能找到?”

删除他们能自行查到的内容。计划不是用 Markdown 重现代码库,而是列出执行者无法自行推导的最小差异。执行者已经打开了代码库。他们会阅读你引用的文件,会查找测试辅助函数、现有实现、迁移历史和 trait 签名。无需在计划中复制这些内容。

提交前,对每个步骤都应用可恢复性测试:

  • **测试主体:**执行者可以自行编写种子数据和设置循环——展示断言和调用位置即可。他们无法从其他来源得知哪条断言能锁定规范要求。
  • **行为约定:**执行者可以阅读类似的现有实现——用 file.ext:line-line 指向它。他们无法从中得知这项任务相较于参考实现新增的行为。
  • **引用代码块:**引用应是一个指针(launch.rs:397-400)。执行者会打开文件。将引用的代码粘贴到计划中属于重复内容,一旦底层代码变动,这些内容就会过时。
  • 清理说明:“删除过时注释和孤立的 PgPool 导入”就足够了——执行者可以自行在文件中搜索 PgPool。逐一列出行号(“第 71-72 行、第 117-122 行、第 194 行”)是执行者在实施时该做的事。

未通过可恢复性测试的计划只是冗长,并不具体。**冗长 ≠ 具体。**具体,是用一句话锁定正确的不变量;冗长,则是逐一枚举每个细节,而一个引用就足以说明。

测试编写规范

在每项任务的步骤 1 中编写测试代码时,请遵循以下四条规则。

契约是指一旦被违反,测试就会失败的最少文本。 超出此范围的内容都是臆测。如果测试主体超过约 15 行,你很可能是在重新推导执行者自己就能编写的准备工作。断言才是契约;准备工作只是流程性代码。

展示断言和调用位置。跳过数据填充循环。 测试要固定行为,而非准备工作。压缩测试不需要显式构造 5 个 SessionEntry 值;它需要展示:调用 compact_entries(_, N, summary),对随后 load_entries 返回内容的断言,以及对插入的摘要行 seq 的断言。执行者可以根据现有类型和辅助函数还原数据构造方式。

优先复用;只有找不到合适选项时才自行创建。 在编写新的 make_user()、test_entry()、pty_spawn、模拟 DB 连接池或 fixture 之前,先在代码库中搜索形态相同的现有实现。计划中新增辅助函数应是例外,而非默认做法。现有辅助函数已经包含计划本需重新推导的规范做法,例如正确的清理方式、真实的数据形态和符合项目惯例的错误处理。如果计划必须引入新的辅助函数,请指出曾考虑过的某个具体现有辅助函数,并解释它为何不适用。“我没搜索”不是理由。如果计划提到由执行者编写的辅助函数,请写明其签名(seed_entries(&store, session_id, count: i64)),但不要在计划正文中实现它。

锁定规范,不要覆盖所有能想到的边缘情况。 测试的目的是证明满足某项具体规范要求,或关闭某种具体故障模式(在规范或假设审查中指出)。目标是:规范中每项行为对应一个精确测试,每个明确指出的 bug 类对应一个测试。如果你发现自己在为同一个函数编写“以防万一”的第 5 个边界测试,请停下来——考虑到维护成本和它给测试套件增加的噪声,额外覆盖的收益很可能已经为负。对输入空间的臆测性穷举应放在基于属性的测试或模糊测试 harness 中(如果项目有的话);否则就是过度设计。YAGNI 不仅适用于实现,也适用于测试。

例外——负载保留不变量。 如果测试锁定了保留/恢复/转换不变量(输出在截断后仍保留、数据能够往返、顺序保持不变),那么结构上不同的数据生产路径,以及受损区域,都不是臆测的边缘情况——它们就是规范。枚举所有数据路径不同的生产者(带逐出机制的流式处理与完整字符串处理),并分别断言受损区域中的哨兵值。YAGNI 不能成为把这些测试简化为单一正常路径生产者的理由——恢复测试正是因此会在存在 bug 的那一个工具上通过。

行为契约规范

每个实现步骤下的行为契约有两条规则。

目标是 3–5 条要点。超过 5 条时,将其余内容替换为参考。 行为契约应列出此任务实现中新增或不同的内容。具体形态、错误处理、编解码器和辅助函数等,都已包含在所引用的类似实现中。如果你写 12 条要点来描述类型、索引、字段和理由,那就是在用 Markdown 重新推导实现。替换为:Schema matches <reference migration file> with <one-sentence delta>。

参考应指向代码,而不是粘贴代码。 参考应是带行号范围的文件路径:core/osprey-core/src/session/pg.rs:271-309。在“Reference:”下方内嵌代码块是一种反模式——执行者打开文件时本就会阅读这些代码,重复粘贴只会造成冗余,而且底层代码一旦变动,粘贴的内容就会过时。如果你发现自己粘贴了超过一个函数签名的内容,就说明你已经把参考变成了重新实现。停下来,改用文件和行号指针。

清理规范

每项修改现有文件的任务都必须以一次清理收尾:移除此次更改导致过时的内容。这是任务的一部分,不是单独的阶段。

清理范围包括本任务涉及的文件中的以下内容:

  • 引用了旧行为、名称或签名的注释(例如,函数现在返回 Arc<dyn Store> 时,注释仍写着 // returns the PG pool)
  • 仅被此次更改删除的代码使用的导入
  • 仅被此次更改替换的调用点使用的函数参数、结构体字段、枚举变体或辅助函数
  • 无用的匹配分支、不可达分支、未使用的私有函数
  • 文件或其函数中过时的文档注释——尤其是不再起关键作用的阶段、PR 或工单引用

如果任务添加了新内容,却留下旧注释、导入或无用的辅助函数,那就还没完成——它交付的是一个不完整的更改,还让下一位读者不得不费力辨别哪些内容仍然有效。计划应明确列出清理步骤:每项任务的第 5 步提交都要准确列出所涉及的文件,执行者暂存这些文件时就是进行清理的时机。

例外:

  • 只创建新文件的任务无需清理。
  • 只编辑配置(Cargo.toml、package.json、CI YAML)的任务只需清理这些文件。

这与专门处理其他任务未涉及文件中残留内容的 Cleanup 任务不同。两者可以同时出现在同一计划中,但处理的是不同的遗留问题。每项任务都必须执行清理,可避免重构后在刚修改的文件中留下残留内容这一常见问题。

不留占位内容

每个步骤都必须包含执行者所需的实际内容。以下内容都属于计划失败——绝不能写:

  • “TBD”、“TODO”、“稍后实现”、“补充详细信息”、“待定”
  • “添加适当的错误处理”/“添加验证”/“处理边缘情况”——却没有明确指出是哪些错误、哪些验证规则、哪些边缘情况
  • “为上述内容编写测试”——却没有说明测试必须作出什么具体断言
  • 没有进一步说明的“与任务 N 类似”——重复内容的正确处理方式见下文的模式
  • 没有精确断言的测试步骤、没有精确命令的命令步骤、没有精确消息的提交步骤
  • 引用了任何未在任务中定义或代码库中已有的类型、函数或方法

实现步骤下的行为约定不是占位内容——它是执行者据以实现的明确约定。禁止的是没有约定的含糊表述;要求的是不包含臆测代码的具体约定。

模式:命名一次,避免重复

当同一种转换适用于多个位置时(例如“将 N 个调用点转换为新 API”“将 N 个测试文件迁移到新 fixture”),应在计划顶部的 模式 部分命名该模式一次,以保持精简,然后在每项任务中引用它。每项使用该模式的任务仍需:

  • 指明具体文件(不要写“见文件列表”——列表应列在任务中)
  • 编写包含实际断言的测试步骤
  • 有自己的提交和提交信息

模式部分只涵盖转换的形式和参考示例,绝不涵盖测试或提交。这样,下游 Agent 可以一次执行一项任务,无需阅读其他任务即可理解,同时也不用让计划把同一段话写 49 遍。

示例:某项任务将一个文件中的 14 个查询调用点转换为新模式,并引用该模式;其测试需断言转换后该文件的测试仍然通过;其提交仅包含该文件。另一项任务将另一个文件中的 4 个调用点转换为同一模式,并有自己的测试和提交。

模式应用审计。 当某个模式应用于多个位置时,计划必须在最后一项位置转换任务之后,立即加入一个最终的 Audit: <pattern name> 任务。审计任务包含三个步骤:

  1. 通过 grep 确认不再有旧模式位置。 给出准确命令;预期输出为空。
  2. 列出与生产配置的差异。 遍历每个已转换的位置,指出哪些位置依赖新模式未复现的生产专用配置(连接池设置、超时、隔离级别、环境变量、信号处理器)。审计任务正文必须明确列出这些位置——不能只写“检查这些位置”,而应写明“文件:行号处的位置 A 依赖 X,文件:行号处的位置 B 依赖 Y”。在审计任务中修复每一项(使用自定义 fixture、覆盖辅助函数等),或在继续之前创建后续任务。
  3. 抽查三个随机转换位置,并与生产接线方式核对。 选择三个位置,运行相应的生产接线测试(根据项目的分层规则,使用 tier-2 或 tier-3),并断言转换后的测试仍覆盖原始错误类别。如果任何抽查位置出现回归,该模式就需要按位置设置例外处理,并在审计中注明。

审计不是风格上的步骤。对 N 个位置盲目应用模式,正是生产配置差异(例如,测试连接池配置在不知不觉中偏离生产连接池配置)以测试全绿的状态发布的原因。审计迫使计划制定者逐一列明,并让执行者进行验证。

假设审计

实现计划中包含一些规范未必明确规定的假设。定稿前,列出你做出的假设——数据形状、命名、库的选择、错误语义、持久化边界——并逐项对照规范进行检查。

重新阅读规范点名的文件。 规范对文件或函数的描述可能已经过时或不完整;文件自身的文档注释、文件头或周边代码可能包含规范遗漏的约束。如果规范中的描述与代码中的关键注释或模式相矛盾,应将其作为假设审计事项提出,而不是盲目相信规范。规范作者往往是凭记忆编写的;代码才是事实依据。

如果某项假设并非由规范明确支持,而且存在合理的其他选择,应在 草稿审查 步骤中提请用户确认。用户确认后,你再继续;用户纠正后,你就修改计划。不要默默自行决定。

在标题下方用简短的“假设”区块记录已确认的假设。后续读者(以及执行 Agent)需要看到这里做出了哪些决定,而不只是查看规范。

自我审查

完成整份计划草稿后,换个角度重新审视规范,并据此检查计划。这是你自己执行的检查清单,不是派发给子 Agent 的任务。

维度检查内容
规格覆盖浏览规格中的每个部分。能否指出一项任务,实现了每项必需要求?列出任何缺漏。
占位内容扫描搜索上述失败模式,并就地修复。
类型一致性后续任务中的类型、签名和名称是否与前面的任务一致?任务 3 中的 clearLayers() 与任务 7 中的 clearFullLayers() 不一致,就是一个错误。
测试规范每项会改变行为的任务,是否都在实现步骤之前包含一个失败测试步骤?
测试层级覆盖列出此计划涉及的所有项目约定第 3 层(或项目定义的等效层级)触发条件——main.rs/入口点、CLI 参数解析、环境变量解析、终端/pty/信号处理、真实的 stdin/stdout 管道、契约依赖 shell 语义的 shell 脚本,以及稳定性属于契约一部分的用户可见字符串字面量。对于每个触发条件,指出计划新增的第 3 层(或等效层级)测试,否则标记该任务为不完整。shell 脚本任务中的 bash 凭据泄露无法通过任何进程内测试发现;只有第 3 层测试才能捕获。
Spike 候选项重新阅读 Assumptions 部分和规格中的 Key Decisions。对于每一条“工具 X 会执行 Y”这类说法,若本仓库或团队都没有可用示例,是否有 Task 0 spike?如果没有,就添加一个或修改规格。
并行实现门槛计划是否在现有 trait 或接口后面新增了第二个后端/平台/适配器?如果是,是否有一个最终任务,针对两种实现运行规范的契约测试套件,并断言可观察行为逐字节一致?如果没有,就添加该任务。
错误传播契约对于每项引入新的可失败操作(序列化/解析/转换/打开/连接)的任务,其行为契约是否说明了错误传播策略?没有明确契约依据的 .unwrap_or(<plausible fallback>) 属于错误类型——修正契约。
消费者检查此计划引入的每个新公共 API 表面(trait 方法、导出的 fn、公有字段、端点、CLI 标志)是否至少有一个具名的生产消费者——即同一计划中非测试路径上的调用方?契约/单元测试不算消费者。如果唯一调用方是测试,就指定生产消费者或移除该表面(标记为延期,并将消费该 API 的工作列为带编号的后续任务)。否则计划不通过——仅为满足契约测试而存在的基础元素是无用的表面,会迫使实现也变得无用。
区分性断言对于每项测试,描述一种合理的错误实现或空操作实现,看看它是否仍能通过断言。如果可以,说明断言针对的对象有误——应将断言移到错误实现会破坏的区域/形状上。对于保留/恢复/转换不变量:在错误实现会损坏的区域中断言一个哨兵值(检查被丢弃的中间部分,绝不要只检查保留下来的头部/尾部),并通过每一种结构上不同的生产者进行测试(会淘汰缓冲区内容的流式生产者,与整字符串生产者并非同一路径)。如果任何测试可能出现误通过,就让计划不通过。
逐任务套件通过每项任务的步骤 4 是否都指定了单项测试命令和更大范围的套件命令?只运行单项测试会隐藏跨任务回归。
模式应用审计如果某个模式适用于许多位置,是否安排了最终审计任务(grep + 枚举生产配置差异 + 对 3 个位置进行抽样验证)?
项目约定计划是否遵循你读取的项目约定(例如 AGENTS.md 或 CLAUDE.md)?(例如,真实路径测试覆盖、注释规范、提交格式)
范围外内容是否有任务偏离了规格标记为范围外的内容?请移除。

如果发现问题,请就地修复。无需重新审查——修复后继续即可。如果发现某项规格要求没有对应任务,请添加该任务。 提交前检查: 只有在每一项都确实为 是 时才继续,不能只是“感觉没问题”。

可选:派遣审阅子 Agent

对于较长的计划(>10 项任务)、不熟悉的领域或高风险工作,可派遣计划文档审阅子 Agent。提示模板见 references/plan-reviewer.md。

对于简短且熟悉的计划,自我审查就足够了。不要为了走流程而派遣——后续的人工审查步骤本来就能发现大多数问题。

审阅草稿

写入磁盘之前,先在聊天中呈现草稿供用户审阅。用户可以要求修改,也可以批准。

呈现内容:

  • 完整的计划 Markdown(放在同一缓冲区中,让用户可以从头到尾阅读)
  • 你做出的假设简表(来自假设审计)
  • 计划将创建或修改的文件列表
  • 指向源规范的链接

认定草稿可供审阅前的检查:

  1. 自我审查清单中的所有维度都确实为 是
  2. 对话中包含具体的草稿正文,而不是摘要,也不是“这是计划的说明”
  3. 每个测试步骤都包含实际测试代码和精确断言;每个命令步骤都包含准确命令;每个实现步骤都包含具体的行为约定(而不是含糊的动词)

如果用户要求修改,请直接修订并再次呈现。在此过程中不要写入磁盘。

编写计划

创建或覆盖 plan.md 前的检查: 只有以下两项都满足时才能写入。

  1. 用户确认关卡: 用户明确批准了草稿,或 指示你保存/写入文件。仅仅表示模糊的赞同不算批准——如果不明确,请先确认。
  2. 路径确认关卡: 目标路径已确定——默认为 .beagle/concepts/<slug>/plan.md,其中 slug 继承自规范所在文件夹。
  • 默认路径: .beagle/concepts/<slug>/plan.md
  • Slug 来源: 继承自规范的父文件夹(.beagle/concepts/ 下的 <slug> 部分)。用户偏好优先于默认路径。
  • 如果用户明确要求提交,请使用:docs: add <slug> implementation plan
  • 写入后,告诉用户:

    "计划已写入 <path>。请在磁盘上审阅;如果需要修改,请告诉我。"

  • 然后准确询问:"你要我生成提示词,以便在新会话中执行此计划吗?"
    • 如果是: 加载 subagent-prompt 技能(../../../beagle-core/skills/subagent-prompt/SKILL.md),并将刚写入的 plan.md 路径指定为源材料,使其源材料和任务分解关卡能够依据计划完成,而无需重新询问用户。
    • 如果否: 告诉用户计划已准备就绪,他们之后可以在新的会话中调用 subagent-prompt 技能来交接,然后停止。
    • 如果无法使用 subagent-prompt(例如未安装 beagle-core):请用户自行调用 subagent-prompt 技能。
  • 在将工作视为完成之前,等待下一条指示。

执行交接

计划是交接文档,不是执行指令。写入后,write-plan 会询问是否立即生成交接提示词:

  • 如果答是: 加载 subagent-prompt 技能(../../../beagle-core/skills/subagent-prompt/SKILL.md),在本会话中生成编排提示词,并以刚写入的 plan.md 为依据。提示词的约定由 subagent-prompt 负责;不要在此处重复说明。
  • 如果答否,或无法使用 beagle-core: 指引用户在新的会话中运行 subagent-prompt 技能,或使用项目提供的其他下游执行技能。
  • 其他情况下,告诉用户计划已准备就绪,他们可以自行逐项推进执行。

不要开始执行。 此技能负责生成计划(以及可选的交接提示词);执行是单独的决定,通常也由另一个具有独立规范的技能负责。

核心原则

  • 规范是契约——绝不臆造规范未明确规定的要求
  • 始终拆分为小步骤——每步耗时 2–5 分钟,绝不捆绑多个步骤
  • 测试是契约;实现是对契约的满足——测试步骤中展示真实的测试断言和调用点;实现步骤中展示行为契约(文件 + 3–5 条要点 + 类似实现的参考)。执行者应依据测试编写代码,而不是依据你的猜测。
  • 默认采用 TDD——每次都先编写失败的测试,再实现
  • 单一事实来源——规范定义 WHAT;计划在契约层面定义 HOW;执行者在代码层面定义 HOW
  • 可恢复性测试——删除执行者通过阅读所引用文件即可恢复的任何内容;冗长不等于具体
  • 契约是最精简的文本:一旦违反,测试就会失败——任何超出契约的内容都是猜测。测试主体超过约 15 行、行为契约超过 5 条要点,以及包含的不只是函数签名的“Reference:”代码块,都是计划在重新推导实现的信号
  • 引用用于指向,不要粘贴——file.ext:line-line 就是引用;“Reference:”下方的内联代码块会在底层代码变动时立即过时
  • 通过 Patterns 遵循 DRY,避免重复——当某种转换适用于 N 个位置时,只命名一次这种模式;每项任务仍须负责自己的文件、测试和提交
  • 测试复用现有脚手架——发明新方案前先用 grep 搜索;若计划中要新增辅助工具,必须指出一个不适用的现有工具
  • 测试也要遵循 YAGNI——但保留载荷不变式除外——锁定规范和已知缺陷类别,而非所有可能的边界情况;穷举猜测的输入空间属于过度设计。但对于保留、恢复、转换不变式,结构不同的生产者和受损区域本身就是规范——列出每个生产者,并断言受损区域中的哨兵值
  • 收尾时进行清理——每项修改文件的任务都应以清除该文件中孤立的注释、未使用的导入、无用的参数/字段/辅助工具结束;用通俗语言描述清理目标,不要写行号——执行者会用 grep 搜索
  • 明确列出假设——将假设显式写入计划,而不是悄悄融入任务;重新阅读规范中提到的文件,不要盲信规范对这些文件的描述
  • 遵循项目惯例——每个项目都有自己的测试命令、提交惯例、注释政策和测试分层规则;阅读项目惯例(例如 AGENTS.md 或 CLAUDE.md,以及 CONTRIBUTING.md 等同类文件),并据此制定计划
  • 计划应能独立执行——下游 Agent 无需重新阅读规范即可执行计划

这项技能不适用的情况

这项技能假定:

  • 已有规范(如果没有,请使用 brainstorm-beagle)
  • 工作范围限于一个内聚的系统(如果不是,请在头脑风暴期间拆分)
  • 下游执行者是具备某种 TDD 意识的 Agent 或工程师

如果工作只是单行修复、单文件内的重构或实验性探索,那么完整计划就过于繁琐——请告知用户这项技能过于笨重,并建议他们直接动手。

评论

支持 Markdown