mcpField
B
bmad-loop-resolve

bmad-loop-resolve

github.com/thecontstructAgent 工作流074 次安装5 周前更新
代码仓库

关于 bmad-loop-resolve

用于处理 bmad-loop 故事暂停的交互式技能,适用于严重升级导致实现无法安全继续的情况。它协助人与会话厘清冻结规格、记录决定并恢复运行,同时处理已保存的审查补丁和工作树隔离。

主要功能

  1. 01读取升级上下文与冻结规格
  2. 02提供选项供人类决策
  3. 03更新规格与解决标记
  4. 04处理已保存的审查补丁
  5. 05考虑重新运行时的工作树行为

适用场景

  1. 01解决规格意图矛盾或缺失
  2. 02澄清未回答的实现问题
  3. 03严重升级后恢复运行
  4. 04在支持时恢复补丁以供审查

安装

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

$npx skills add https://github.com/thecontstruct/bmad-loop --skill bmad-loop-resolve

安装后在 Claude Code 中输入/bmad-loop-resolve确认已加载。

详细介绍

bmad-loop 升级问题解决

一次 bmad-loop 运行推动某个故事从开发阶段进入评审阶段时,会话触发了严重升级(工作无法安全继续——通常是因为 冻结规范 中存在矛盾或尚未回答的问题),编排器因此暂停了整个运行,等待人工处理。触发升级的会话已经结束;你现在是一个全新的交互会话,任务是与人工一起消除歧义并更新冻结规范,以便编排器可以重新启动该故事,并依据修正后的规范再次推动它。

这是一个交互式流程:人工在场。提出问题、提供选项并给出建议——但由人工做决定。(本会话特意不设置 $BMAD_LOOP_MODE;不适用“不得提问”的自动化规则。)

身份与输入/输出约定

已设置以下环境变量:

  • $BMAD_LOOP_RUN_DIR — 已暂停运行的目录。
  • $BMAD_LOOP_STORY_KEY — 触发升级的故事键(也是你的调用参数)。
  • $BMAD_LOOP_RESOLVE_CONTEXT — 为你编写的 context.json 文件路径。

**首先读取 $BMAD_LOOP_RESOLVE_CONTEXT。**其架构如下:

{
  "story_key": "6-4-cli-list-command",
  "run_id": "20260613-111429-6a14",
  "project_root": "/abs/path/to/bmad-project",
  "code_root": "/abs/path/to/code-repository",
  "spec_file": "/abs/path/to/_bmad-output/implementation-artifacts/spec-<story>.md",
  "spec_reaches_the_redrive": true,
  "redrive_base_ref": "<branch the re-drive reads, or HEAD>",
  "baseline_commit": "<sha>",
  "paused_reason": "CRITICAL escalation from review session: ...",
  "escalations": [
    {
      "type": "<kind>",
      "severity": "CRITICAL",
      "detail": "<what's ambiguous/contradictory>"
    }
  ],
  "resolution_path": "/abs/path/to/<run>/resolve/<story>/resolution.json"
}

escalations 数组按时间倒序排列,最新的在前。 在收集到的整个上下文中,每个不同的升级事件恰好出现一次。

交互会话的工作目录始终是 project_root。该目录树中包含你需要检查或澄清的 BMAD 工件和规范。code_root 是本次运行的代码和 Git 工作所在的目录树;它可能与前者不同。若两个根目录不同,请勿误把会话当前工作目录当作代码检出目录:人工需要进行的任何代码修复或提交都应在 code_root 下完成,而工件和规范工作仍应以 project_root 为准(或使用此上下文中明确给出的绝对路径)。本次解决会话期间,你仍不得实现或提交;指导人工时要指出正确的目录树。

spec_reaches_the_redrive 表示你的编辑是否会在后续流程中生效。重新推动流程时会读取一棵目录树;spec_file 可能指向另一棵。在工作树隔离模式下,重新推动流程读取任何内容之前,运行挂载都会被丢弃,因此挂载中的规范也会随之销毁。若此字段为 false,对 spec_file 的任何写入仍会成功,随后却会被丢弃——这比完全不编辑更糟,因为会话看起来像是已解决问题。null 表示没有可编辑的常规冻结规范:要么任务没有记录规范,要么 stories 模式记录的是哨兵路径。这两种情况下,步骤 4 都不适用;若存在下方的哨兵指导,请按其操作。

**redrive_base_ref 指明适用哪种补救方式。**在告知人工任何信息之前先读取它:分支名称和 HEAD 含义相反。

即便字段值为 false,也不要跳过编辑——修正后的规范会被保留下来,也是你和人工达成一致的最明确记录。照常执行步骤 4,然后在说明解决方案的同时,告知人工修正必须落到哪里才能被读取——由该字段决定:若 redrive_base_ref 指向某个分支,就在 redrive_base_ref 上提交;若为 HEAD,则在主检出目录中重新应用修改,但不要提交。下方两段分别说明这两种情况。

对此必须准确,因为两个看似合理的做法都会悄无声息地失败:

  • 从主检出目录提交,无法包含你编辑的文件——它位于一个链接的单元工作树中,那是独立的工作树。
  • 在单元自己的分支上提交,也无法让重新推动流程读取到修改。替换工作树会从 redrive_base_ref 新建,而非从已丢弃挂载所在的分支创建。

因此,修正必须到达 redrive_base_ref 本身:在该目录树中的规范副本上进行相同修改,并在那里提交。编排器重新启动时会指定同一个引用;请在此处告知人工,以便他们在结束会话前知晓,而不是结束后才知道。 当 redrive_base_ref 为 HEAD 时,切勿让他们提交任何内容。 这表示重新运行会在主检出目录中执行,并读取其工作树,因此会直接读取其中的编辑内容。HEAD 基础引用旁边的 spec_reaches_the_redrive: false 与上面的问题恰好相反:spec_file 指向的是本次运行已停止使用的工作树,因为该故事处于升级状态期间,其隔离策略发生了变化。解决办法是在主检出目录中的规范副本里进行相同的编辑——无需提交,也无需分支。此时让他们提交,会把他们引向重新运行不会读取的工作树,这会造成相反方向的同类工作丢失。

在故事模式(按文件夹和 ID 分派)下,上下文还包含一个 stories 块——即此故事在清单中的意图,因此你无需费力查找,就能了解它要做什么:

{
  "stories": {
    "spec_folder": "_bmad-output/epic-1",
    "story": {
      "id": "6-4-cli-list-command",
      "title": "CLI list command",
      "description": "…",
      "spec_checkpoint": false,
      "done_checkpoint": false,
      "invoke_dev_with": "…free-text planner→dev note, or ''…"
    },
    "sentinel": {
      "kind": "unresolved",
      "path": ".../stories/6-4-cli-list-command-unresolved.md",
      "blocking_condition": "…the reason planning halted…"
    }
  }
}

只有当升级的故事是哨兵时才会包含 sentinel 子块(参见下文的故事模式部分);普通升级不会包含此子块。

你的输出标记是 resolution_path 指向的文件。成功解决问题时,写入该文件是最后一步。架构如下:

{
  "story_key": "<key>",
  "decision": "<one or two sentences: the rule you and the human chose>",
  "spec_file": "<the spec you edited>",
  "spec_updated": true,
  "restore_patch": "<optional: path to a saved intent-gap patch to re-apply>"
}

restore_patch 是可选的,仅用于下文介绍的意图缺口补丁还原情形——普通解决方案中应完全省略它。

你必须做的事

  1. 阅读上下文,然后完整阅读 spec_file 中的冻结规范——尤其是 <frozen-after-approval> 区块(开发/审查会话视为权威依据的意图)。升级问题几乎总是因为此区块未提及实现遇到的情况,或与之矛盾。

  2. 向用户清楚说明当前暂停的证据:

    • 当 escalations 数组非空时,按现有的最新优先顺序呈现其中记录的条目。不要用 paused_reason 替代已记录的升级详情。
    • 当 escalations 数组为空时,首先要求 paused_reason 是包含至少一个非空白字符的文本。如果缺失、为 null、非文本,或去除首尾空白后为空,则报告 resolve 上下文格式错误,不要写入 resolution 标记。否则,原样呈现 paused_reason,作为当前暂停的可用证据,并说明没有更新的已记录升级详情。不要读取水位线以下的内容,不要取消筛选或恢复较早工件中的升级信息,也不要根据 paused_reason 合成升级对象。

    使用选定的证据,说明哪些地方含糊或矛盾、为何会阻碍安全实施,并提供 2–4 个具体的解决选项,明确给出建议及其权衡。保持简洁——引用相关规范原文。

  3. 取得用户的决定。 如果选择不明确,请追问。不要臆造需求;如果用户拿不定主意,帮助他们分析,不要猜测。

  4. 更新冻结规范,明确无歧义地记录决定:修改 <frozen-after-approval> 区块,以及任何受影响的验收标准/测试矩阵行,使新的开发会话只有一种正确解读。做出消除歧义所需的最小改动。如果需要大幅修改规范,可以使用 bmad-spec 或 bmad-correct-course 技能。如果 spec_reaches_the_redrive 为 false,进行相同的修改,然后明确说明此副本不是 re-drive 所读取的副本,并指出 redrive_base_ref 选定的补救方式:若为分支,必须将更正提交到 redrive_base_ref;若为 HEAD,必须在主检出中重新应用更正,并保持未提交——未标记的修改会丢失;在错误的工作树或错误分支上提交,则是看似完成、实则会丢失的工作。

  5. 在 resolution_path 写入 resolution 标记(使用上述架构),然后告知用户已记录该决定,他们可以退出本会话——编排器将提供选项,供其重新启用故事并继续运行(基于更正后的规范进行干净重建)。

特殊情况:评审阶段出现 intent gap,且已保存补丁

如果升级是由评审步骤因 intent gap 而中止触发的,开发会话会先将尝试的更改保存为补丁文件(位于实现产物文件夹中),然后还原工作树——升级 detail 和规格说明中的 ## Review Triage Log 都会引用补丁路径。该补丁是具体证据:它准确展示了本次运行实现的是对意图的哪种解读。

首先检查上下文文件中的 restore_supported。 如果其值为 false(工作树隔离运行:重新驱动会丢弃并重新挂载单元的工作树,因此无法原位还原;没有记录规格说明的升级:还原后的补丁没有可恢复的评审;规划前哨兵卡住:没有尝试过的实现可供还原),绝不要提供还原选项,也绝不要记录 restore_patch——编排器会拒绝该解决方案,整个会话的协商都会白费。补丁仍可用作证据。

通过两种方式使用补丁:

  • 作为证据。 阅读补丁(以及它所代表的差异),看看推测的解读会产生什么结果——这通常比单看问题更有助于撰写澄清内容。

  • 当实际尝试的解读是正确的。 有时本次运行的推测是正确的,只是意图中没有明确说明。将此作为明确选项提供给用户:"实现将其解读为 X,而这确实是我们想要的——修订意图,明确说明 X,然后在已写好的更改上恢复评审,而不是重新实现。" 如果用户选择此项:

    1. 仍然要在规格说明中修订意图,使其明确无歧义地表述为 X(上文第 4 步不变——冻结的意图必须与还原后的代码一致)。
    2. 将 "restore_patch": "<the saved patch path>" 添加到 resolution.json 中(从升级详情/分流日志中逐字复制路径)。

    随后,编排器会将规格说明重新置为 in-review,把补丁重新应用到基线上,然后再次派发——会话将从还原后的差异进入评审步骤。不要自行执行 git apply 应用补丁,也不要设置规格说明状态——编排器会在重新启用时以确定方式完成这两项操作。

    还原操作不得与解决方案提交产生重叠。 重新启用会将重新驱动的基线推进到分支解决后的 HEAD,但已保存的补丁是基于原始基线生成的——因此,如果本会话留下的提交修改了补丁涉及的文件,执行还原时 git apply 会失败,故事会再次升级(这是有意为之,且会明确报错:编排器绝不会悄悄将解决方案与过时的尝试合并)。如果解决工作已经包含或取代了尝试的更改,省略 restore_patch——重新启用后这些提交会保留为重新驱动的起点,因此从头开始的重新驱动会直接在其基础上构建。

如果尝试的解读是错误的(这是常见情况),则完全省略 restore_patch:编排器会依据修正后的意图从头重新驱动。

你绝不能做的事

  • 不要编写协调器的 result.json——那是开发/审查产物;当前不是这类会话。
  • 不要更改 sprint-status.yaml,也不要设置规范的 status: 字段——协调器会在恢复时确定性地重新启用规范状态。只编辑规范内容。
  • 不要实现故事、编写功能代码、运行测试或提交。你的工作到修正规范并写入解决标记为止。即使 spec_reaches_the_redrive 为 false,也仍然如此:将修正后的规范放到重新驱动流程读取的位置是 HUMAN 的步骤——如果 redrive_base_ref 指向某个分支,就在该分支上提交;如果它是 HEAD,就在主检出中重新应用。告诉他们这是必须做的,以及该在哪儿做;不要自行操作。
  • 不要扩大范围。只解决被升级的歧义;如果发现无关问题,告知 HUMAN,但不要处理。

Stories 模式:哨兵文件与保留副本

在 stories 模式下,若某个故事甚至无法规划——开发会话在编写真正的规范之前就遇到矛盾或信息缺失——系统会留下一个固定 slug 的哨兵文件,而不是冻结规范:<id>-unresolved.md(意图过于模糊,无法规划)或 <id>-ambiguous.md(有多份故事规范与该 id 匹配)。上下文中的 stories.sentinel 区块会指出该文件,并包含会话记录的 blocking_condition。

哨兵文件不是可供编辑的规范——其中没有计划或 <frozen-after-approval> 区块。因此,对于哨兵文件:

  • 不要尝试修订冻结规范(步骤 4 中的“编辑冻结规范”不适用——这里并不存在冻结规范)。应解决上游歧义,以便新的规划流程能够成功:通常需要与 HUMAN 一起澄清 SPEC.md(史诗规范),或此故事在 stories.yaml 中的条目——规划器读取的 title / description / invoke_dev_with。
  • redrive_base_ref 决定上游编辑必须落到哪里,与规范的情况完全相同。spec_reaches_the_redrive 无法回答这个问题——它针对的是 spec_file,而对于哨兵文件,该文件将被删除。你实际编辑的产物是 SPEC.md / stories.yaml,它们面临同样的问题:当 redrive_base_ref 指向某个分支时,重新驱动流程会挂载一个新的工作树,并从该分支的已提交树重新规划,因此未提交的编辑不可见,重新规划会再次生成相同的哨兵文件——告诉 HUMAN 必须在该分支上提交。当它是 HEAD 时,重新驱动流程会在主检出的工作树中重新规划,并直接读取编辑内容——不要告诉他们提交。协调器会依据相同规则重新启用流程,并会等到该分支包含这些更改后才恢复。
  • 重新启用时,协调器不会将哨兵文件切换为 ready-for-dev(没有计划可供分发)。它会将哨兵文件的副本保留为 {run}/sentinels/<id>-<kind>.md,作为线索,删除原哨兵文件;下一次分发时会从头重新规划该故事(对于 spec_checkpoint 故事,会再次执行第 1 阶段)。你自己不要触碰哨兵文件。
  • HUMAN 决定如何消除歧义后,照常编写解决标记;将 spec_file 设为你编辑的文件(例如 SPEC.md),如果修复完全在 stories.yaml 中完成,则可以省略该字段。
并非哨兵:有多个文件匹配该 id

这不同于上文的单文件 <id>-ambiguous.md 哨兵:当 stories/ 中有多个文件匹配 <id>-*.md(例如 3-login.md 和 3-signup.md)时,id 本身在 磁盘上 存在歧义,编排器会卡住该故事,不选择任何一个文件。你可以通过升级原因(ambiguous story file match: <names>)以及上下文中缺少的内容来识别这种状态:没有 stories.sentinel 块,也没有单一的规格路径。

上述自动清除机制不适用——这里没有需要保留并删除的哨兵,而且仅重新布防只会因相同的重复文件再次卡住。解决办法就是清理:与人工审核者一起确定哪个文件才是该故事的实际规格,并删除或重命名另一个文件(如果两个文件都包含实际工作内容,请先合并;重命名时必须将其移出 <id>-* 模式或改用另一个 id)。匹配到一个文件时,会重新派发该规格;匹配到零个文件时,会从头重新规划。然后像往常一样写入解决标记——重新布防并恢复运行后,后续流程会自动处理。

如果无法解决

如果人工审核者决定暂缓、确实无法获取所需信息,或正确的修复超出规格编辑的范围(例如需要修改 PRD/架构),请明确说明,不要写入解决标记。不写入标记就退出,会使故事继续处于升级状态并暂停运行——这是安全的默认行为。编排器不会重新布防没有记录解决结果的故事。

评论

支持 Markdown