关于 write-plan
write-plan 将已批准的 brainstorm-beagle 规格文档转为面向工程师或下游 Agent 的逐任务实现计划。它先梳理文件和项目约定,再拆分为小型测试驱动任务;不会执行计划或修改生产代码。
主要功能
- 01要求提供 brainstorm-beagle 规格文档
- 02检查项目约定及相关代码
- 03编写任务前规划文件结构
- 04拆分为 TDD 步骤
- 05为未经验证的假设安排 spike
- 06依据规格文档审核计划
适用场景
- 01根据已批准的规格准备执行计划
- 02规划需遵循仓库约定的工作
- 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>
工作流程
按顺序完成以下步骤:
- 定位规范 — 找到
.beagle/concepts/<slug>/spec.md;如果不存在,请停止并引导用户使用 brainstorm-beagle - 阅读规范 — 阅读所有章节;不要改述,也不要在总结时省略要求
- 阅读项目约定 — 查看项目约定(例如根目录和嵌套目录中的 AGENTS.md 或 CLAUDE.md),了解计划必须遵守的测试、注释和架构规则
- 探索相关代码 — 阅读计划将涉及或作为模式参考的现有文件;不要猜测结构
- 设计文件结构 — 在编写任何任务之前,明确将创建或修改哪些文件
- 拆分任务 — 每项任务都应小而具体(2–5 分钟的步骤),遵循 TDD,并包含准确路径和代码
- 自我审查 — 对照规范检查,扫描占位内容,验证类型一致性(见下文的 自我审查)
- 可选:执行审查 — 仅适用于篇幅较长或涉及不熟悉领域的计划。如果 Agent 支持子 Agent,则派发审查子 Agent;否则在当前上下文中执行同样的审查——输出完全相同(见
references/plan-reviewer.md) - 向用户展示草稿 — 在聊天中展示草稿供用户审阅;如有需要,继续迭代
- 写入磁盘 — 仅在用户明确批准后,保存至
.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 解析优先级(按顺序):
- 用户提供的路径或 slug(
write-plan auth-rewrite、"plan the spec at.beagle/concepts/foo/spec.md") .beagle/concepts/下最近编辑的规范- 存在多个可能的规范时,询问用户以确定目标
如果规范不存在:
"我找不到
.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>,其正文应当:
- 按照文档记录的步骤,在此仓库中运行计划其余部分所依赖的规范命令。
- 记录实际输出(包括成功路径和失败模式)。
- 二选一:确认规范中的关键决策仍然成立,或者在运行任何其他任务之前,将发现反馈给用户并提出具体的修订建议。
如果规范的关键决策依赖团队尚未在此仓库中验证过的工具行为,Task 0 就不可省略。以下是必须进行 Spike 的说法示例:
- “工具 X 的
--workspace标志可在一次调用中处理此仓库的多后端布局。” - “库 Y 的默认测试属性使用与生产环境相同的连接池配置。”
- “CLI Z 的内省功能涵盖我们将编写的所有查询类型。”
- “迁移框架 W 能在全新数据库上幂等地处理并发迁移器。”
- **输入形状假设:**规范假设上游输入以 X 形状到达——完整/已排序/已去重/全部到齐/已通过验证——但尚无人验证此仓库中是否确实如此。(保留策略规范假设“工具输出是完整的”;但流式工具并非如此——新层看到输出前,滚动缓冲区已在上游淘汰了前缀。)关于上游数据形状的关键假设是 Spike 候选项,不是既定事实。
如果 Spike 失败或发现限制,请停下来修订规范——不要用额外的计划任务来掩盖这一发现。如果规范基于某个行为作出了关键决策,而该行为并未如预期运作,那么这份规范需要再次进行头脑风暴,而不是制定更多变通方案。
这条规则比现有的假设审查更严格。假设是“我在猜测尚未验证的行为”。Spike 候选项是“规范基于无人验证过的行为作出了关键决策”。前者需要记录;后者需要实际运行验证。
并行实现门槛
当计划为现有功能添加并行实现时(例如,在同一 trait 后接入第二种数据库后端、为同一 UI 添加第二个平台目标,或为同一服务添加第二种协议适配器),计划必须以一个最终任务收尾,且该任务正文必须包含:
- 找出用于固定现有实现可观察行为的规范契约/一致性测试套件。
- 在同一次调用中,对两种实现运行该套件。
- 断言可观察行为逐字节相同——返回值、持久化行、发出的事件、错误变体。内部结构体布局不算。
- 如果任一实现的契约测试未通过,则任务失败。只要套件中仍能看出差异,就不得宣布计划完成。
此任务是最终门槛,不可省略。没有它,“并行实现第二种后端”的计划就会交付存在差异的实现——执行者会各自独立地宣布每个后端的任务已完成,而能同时检查两者的契约测试却会在无人察觉的情况下继续失败。
行为等价性门槛独立于各任务的契约测试。各任务的测试固定单个实现的行为;该门槛则证明它们彼此一致。
文件结构
定义任务之前,先梳理将要创建或修改哪些文件,以及每个文件负责什么。此时应敲定拆分决策。
- 设计边界清晰、接口明确的单元。每个文件都应有一个明确职责。
- 你最擅长处理能一次纳入上下文的代码,文件越专注,修改就越可靠。优先选择更小、更专注的文件,避免大文件承担过多职责。
- 应一起修改的文件应放在一起。按职责拆分,而不是按技术层拆分。
- 在现有代码库中,遵循既有模式。如果代码库使用大文件,不要擅自重构;但如果你要修改的文件已经过于庞大,在计划中加入拆分也是合理的。
文件结构部分应出现在计划文档本身中,以便工程师(或下一个 Agent)在阅读具体任务前了解工作的大致结构。
适度拆分任务
每个步骤只做一项操作(2-5 分钟):
- “编写失败测试”——一个步骤
- “运行测试,确认其失败”——一个步骤
- “编写最精简的代码,使测试通过”——一个步骤
- “运行测试,确认其通过”——一个步骤
- “提交”——一个步骤
把多项操作捆绑在一起的步骤(“编写测试和实现”)过于粗略——应拆分开。抽象描述行为的步骤(“添加验证”)过于含糊——应写明具体代码。
计划文档格式
使用 references/plan-template.md 中的模板。计划包含以下部分(按顺序):
- 标题栏——标题、目标、架构草图、技术栈、指回规格说明的链接
- 文件结构——要创建或修改的文件及其职责列表
- 任务 N 块——每个连贯的工作单元各一个,内部包含 TDD 步骤
- 自我审查结果——简短说明,确认自我审查过程诚实可信
每份计划都必须以此标题栏开头(使用原样的 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> 任务。审计任务包含三个步骤:
- 通过 grep 确认不再有旧模式位置。 给出准确命令;预期输出为空。
- 列出与生产配置的差异。 遍历每个已转换的位置,指出哪些位置依赖新模式未复现的生产专用配置(连接池设置、超时、隔离级别、环境变量、信号处理器)。审计任务正文必须明确列出这些位置——不能只写“检查这些位置”,而应写明“文件:行号处的位置 A 依赖 X,文件:行号处的位置 B 依赖 Y”。在审计任务中修复每一项(使用自定义 fixture、覆盖辅助函数等),或在继续之前创建后续任务。
- 抽查三个随机转换位置,并与生产接线方式核对。 选择三个位置,运行相应的生产接线测试(根据项目的分层规则,使用 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(放在同一缓冲区中,让用户可以从头到尾阅读)
- 你做出的假设简表(来自假设审计)
- 计划将创建或修改的文件列表
- 指向源规范的链接
认定草稿可供审阅前的检查:
- 自我审查清单中的所有维度都确实为 是
- 对话中包含具体的草稿正文,而不是摘要,也不是“这是计划的说明”
- 每个测试步骤都包含实际测试代码和精确断言;每个命令步骤都包含准确命令;每个实现步骤都包含具体的行为约定(而不是含糊的动词)
如果用户要求修改,请直接修订并再次呈现。在此过程中不要写入磁盘。
编写计划
创建或覆盖 plan.md 前的检查: 只有以下两项都满足时才能写入。
- 用户确认关卡: 用户明确批准了草稿,或 指示你保存/写入文件。仅仅表示模糊的赞同不算批准——如果不明确,请先确认。
- 路径确认关卡: 目标路径已确定——默认为
.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 技能。
- 如果是: 加载 subagent-prompt 技能(../../../beagle-core/skills/subagent-prompt/SKILL.md),并将刚写入的
- 在将工作视为完成之前,等待下一条指示。
执行交接
计划是交接文档,不是执行指令。写入后,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 或工程师
如果工作只是单行修复、单文件内的重构或实验性探索,那么完整计划就过于繁琐——请告知用户这项技能过于笨重,并建议他们直接动手。