bmad-loop-resolve について
bmad-loop-resolveは、一時停止したbmad-loopのストーリーに関するエスカレーションを、人と対話して解決するスキルです。曖昧さを整理し、基準となる仕様を更新して解決内容を記録し、オーケストレーターによる実行再開に備えます。
主な機能
- 01エスカレーション情報と仕様の確認
- 02証拠と解決案の提示
- 03人との対話による決定の明確化
- 04仕様と関連する受け入れ基準の更新
- 05解決マーカーの書き込み
活用シーン
- 01ストーリー実行を妨げる矛盾の解決
- 02仕様に残る未回答の質問の明確化
- 03ストーリー再実行前の決定記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bmad-code-org/ bmad-loop --skill bmad-loop-resolveインストール後、Claude Code で/bmad-loop-resolveを入力して読み込まれたか確認します。
同梱ファイルbmod.toml
詳細
bmad-loop エスカレーションの解決
bmad-loop の実行でストーリーを開発 → レビューまで進めたところ、セッションで
重大なエスカレーションが発生しました(安全に作業を続けられない状態です。通常は
frozen spec に矛盾があるか、未回答の質問があります)。オーケストレーターは人間の対応を
待つため、実行全体を一時停止しました。エスカレーションを起こしたセッションは終了しており、
あなたは新しい対話セッションです。あなたの役割は、人間と曖昧な点を解決し、frozen spec を
更新することです。これにより、オーケストレーターはストーリーを再び有効化し、修正済みの仕様に
基づいて再実行できます。
これは対話型です。人間が参加しています。質問し、選択肢を提示し、推奨案を示してください。
ただし、決定するのは人間です。このセッションでは $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: ...",
"env_fault_site": null,
"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 は、編集内容が再実行時に反映されるかどうかを示します。 再実行では
1つのツリーが読み込まれますが、spec_file は別のツリーを指している場合があります。ワークツリーが
分離されている場合、再実行が読み込みを行う前に実行時のマウントが破棄されるため、そのマウント内の
仕様も一緒に消えてしまいます。このフィールドが false の場合、spec_file への書き込みは必ず
成功しますが、その後破棄されます。セッション上は解決済みに見えてしまうため、編集しないよりも
悪い結果になります。null は、通常の frozen spec を編集できないことを意味します。タスクに仕様の
記録がないか、stories モードでセンチネルパスが記録されているかのいずれかです。どちらの場合も手順 4
は適用されません。そのブロックがある場合は、以下のセンチネルに関する案内に従ってください。
redrive_base_ref は、2つの対処方法のどちらを適用するかを示します。 人間に何かを伝える前に
必ず読み込んでください。ブランチ名と HEAD では、適用すべき方法が正反対です。
値が false でも、編集を省略しないでください。修正した仕様が引き継がれるものであり、あなたと人間が
合意した内容を最も明確に示すものです。通常どおり手順 4 を行い、解決内容とあわせて、修正を読み込み
可能な場所に反映する必要があることを人間に伝えてください。どこに反映するかはこのフィールドで
決まります。redrive_base_ref がブランチ名の場合は、そのブランチにコミットします。HEAD の場合は、
メインチェックアウトに再適用し、コミットせずに残します。以下の2つの段落で、それぞれのケースを説明します。
よくある次の2つの対応では、どちらも何も起きないまま失敗するため、正確に説明してください。
- メインチェックアウトからコミットしても、編集したファイルは含まれません。リンクされたユニットの ワークツリーにあるため、別の作業ツリーになっています。
- ユニット独自のブランチにコミットしても、再実行には反映されません。置き換え用のワークツリーは、
破棄されたマウントのブランチではなく、
redrive_base_refから新しく作成されます。
そのため、修正内容は redrive_base_ref 自体に反映する必要があります。そのツリーにある仕様のコピーにも
同じ編集を行い、そこでコミットしてください。オーケストレーターはストーリーを再び有効化するときにも
同じ ref を指定します。セッションを終了した後ではなく、終了前に人間が把握できるよう、ここで伝えてください。
redrive_base_ref が HEAD の場合、コミットを指示してはいけません。 つまり、
再実行は メインのチェックアウト で行われ、作業ツリーを読み取るため、そこでの編集は
そのまま読み取られます。HEAD のベースの横にある spec_reaches_the_redrive: false は、
上記とは逆の問題です。ストーリーがエスカレーションされたままになっている間に分離ポリシーが変更され、
spec_file がこの実行では使用を STOP したワークツリーを指しています。解決策は、
メインのチェックアウトにある仕様書のコピーにも同じ編集を行うことです。コミットも
ブランチも不要です。ここでコミットを指示すると、再実行が読み取らないツリーに誘導することになり、
逆方向の同じ作業損失につながります。
ストーリーモード(フォルダー+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 サブブロックが含まれるのは、エスカレーションされたストーリーが センチネル
の場合のみです(下記のストーリーモードのセクションを参照)。通常のエスカレーションでは
省略されます。
チケットモード(BMAD v7 のイニシアチブチケットツリー)では、spec_file はチケットの
計画を指し、コンテキストには tickets ブロックも含まれます。チケットと計画の
現在の内容が記載されています。
{
"tickets": {
"ref": "1.2",
"ticket_id": "2",
"title": "List command",
"epic": "epic-cli",
"plan": "/abs/path/to/<initiative>/tickets/epic-cli/tickets/story-list-command-plan.md",
"plan_status": "blocked",
"blocked_reason": "intent gap",
"auto_run_result": "…excerpt of the plan's `## Auto Run Result`…"
}
}
計画に該当する値がない場合、存在しない場合、または読み取れなかった場合、
plan_status、blocked_reason、auto_run_result は null になります。計画の
フロントマターが欠落または不正な場合も、plan_status と blocked_reason は
null になります(オーケストレーターは読み取り不能な計画と不正なフロントマターを記録します)。
計画の blocked_reason は、build-auto が停止した条件です。オーケストレーターは、
チケットを再アームするときにこれをクリアします。
出力マーカーは 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 は任意で、以下の意図ギャップに対するパッチ復元の場合にのみ使用します。
通常の解決では、項目ごと完全に省略してください。
必ず行うこと
-
コンテキストを読み、続いて
spec_fileにある凍結済み仕様書を全文読みます。 特に<intent-contract>ブロック(v7 チケット計画。古い仕様書では<frozen-after-approval>)を確認してください。これは開発セッションやレビュー セッションで正式な根拠として扱われる意図です。エスカレーションの原因は、ほとんどの場合、 実装で遭遇したケースについて、このブロックに記述がないか、内容が矛盾していることです。 -
現在の一時停止に関する根拠を、人間に明確に提示します。
escalations配列が空でない場合は、記録された項目を既存の新しい順で提示します。 記録されたエスカレーションの詳細をpaused_reasonに置き換えてはいけません。escalations配列が空の場合は、まずpaused_reasonが空白以外の文字を少なくとも 1 文字含むテキストであることを確認します。欠落している場合、nullの場合、 テキスト以外の場合、またはトリミング後に空の場合は、解決コンテキストの形式が 不正であることを報告し、解決マーカーを書き込まないでください。そうでなければ、 現在の一時停止に関する入手可能な根拠としてpaused_reasonをそのまま提示し、 新しい記録済みエスカレーションの詳細がないことを明示します。ウォーターマークより 前を読み取ったり、フィルターを解除したり、古いアーティファクトのエスカレーションを 復元したり、paused_reasonからエスカレーションオブジェクトを合成したりしてはいけません。
選択した根拠を使って、何が曖昧または矛盾しているのか、それが安全な実装を妨げる理由を 説明し、明確な推奨案とそのトレードオフを添えて、具体的な解決策を2~4個提示します。 要点を絞り、関連する仕様書の行を引用してください。
-
人間の判断を得ます。 選択が明確でない場合は、追加で質問してください。要件を 作り上げてはいけません。人間が判断に迷っている場合は、推測せず、検討を支援します。
-
決定内容が曖昧さなく反映されるよう、凍結済み仕様書を更新します。そのために、
<intent-contract>ブロック(v7 計画。古い仕様書では<frozen-after-approval>)と、影響を受ける受け入れ基準/テストマトリックスの行を 修正します。新しい開発セッションで解釈が一通りに定まるようにしてください。曖昧さを なくすために必要な最小限の変更にとどめます。より大きな変更が必要な場合は、スプリント モードまたはストーリーモードではbmad-specまたはbmad-correct-courseスキル (BMAD v6)を使用してもかまいません。チケットモードではbmad-agent-poを使って チケットを精査または再計画します。spec_reaches_the_redriveがfalseの場合は、 同じ修正を行ったうえで、このコピーは再駆動時に読み込まれるものではないことを明確に 伝え、redrive_base_refで指定される対処法を示します。ブランチの場合、修正はredrive_base_refにコミットする必要があります。HEADの場合は、メインの チェックアウトで未コミットの状態で再適用する必要があります。ここでフラグを立てずに 編集すると作業が失われます。また、誤ったツリーやブランチでのコミットも、完了したように 見えて実際には作業が失われます。 -
resolution_pathに解決マーカーを書き込みます(上記のスキーマに従います)。その後、 解決が記録されたことと、このセッションを終了できることを人間に伝えます。オーケストレーターが ストーリーを再アームして実行を再開するための操作を提示します(修正済み仕様書に基づく クリーンな再構築です)。
特例:パッチが保存された、レビュー段階の intent gap
エスカレーションが、intent gap によってレビューステップが停止したことを起点としている場合、開発セッションはツリーを元に戻す前に、試みた変更をパッチファイル(実装成果物フォルダー内)として保存しています。エスカレーションの detail と仕様の ## Review Triage Log に、パッチのパスが記載されています。このパッチは具体的な証拠です。その実行が意図をどのように解釈して実装したのかを正確に示しています。チケットモードでは、パッチはプランと同じ場所に置かれ、.md に対する .patch という名前になっています。そのパスを restore_patch に指定してください。オーケストレーターはチケットを再アームする際に、パッチをツリーから実行ディレクトリへ移動し、その移動後のコピーを保持します。そうしないと、再実行時のクリーンツリーチェックに失敗するためです。
まずコンテキストファイルの restore_supported を確認してください。 値が false の場合(ワークツリー分離での実行:再実行時にユニットのワークツリーは破棄されて再マウントされるため、インプレースで復元しても適用先がありません。記録された仕様がないエスカレーション:パッチを復元しても再開するレビューがありません。計画前のセンチネルによる行き詰まり:復元する実装がまだありません)、復元オプションを提案せず、restore_patch も絶対に記録しないでください。オーケストレーターが解決を拒否するため、このセッションでの交渉がすべて無駄になります。パッチは引き続き証拠として利用できます。
パッチは、次の2つの方法で使用します。
-
証拠として。 パッチ(およびそれが表す差分)を読み、推測された解釈によって何が生成されたのかを確認します。多くの場合、質問だけの場合よりも、明確化を書くための有用な材料になります。
-
試みた解釈が実際には正しかった場合。 実行時の推測が正しく、意図だけが明記されていなかったということもあります。これを人間に明示的な選択肢として提示してください。「実装ではこれを X と解釈しましたが、実際に望んでいるのはそのとおりです。意図に X と明記し、再実装する代わりに、すでに書かれた変更を使ってレビューを再開します。」 人間がこれを選んだ場合:
- それでも、仕様の意図を修正して、X であることを曖昧さなく記述します(上記のステップ4は変更ありません。凍結された意図は、復元されたコードと一致している必要があります)。
resolution.jsonに"restore_patch": "<保存されたパッチのパス>"を追加します(エスカレーションの詳細/トリアージログからパスをそのままコピーしてください)。
その後、オーケストレーターは仕様を
in-reviewに再アームし、ベースラインにパッチを再適用して、再ディスパッチします。これにより、復元された差分を使って、セッションはレビューステップから再開します。自分でgit applyを実行してパッチを適用してはいけません。また、仕様のステータスも設定してはいけません。再アーム時に、オーケストレーターが両方を決定論的に処理します。復元と解決コミットを重ねてはいけません。 再アームによって再実行のベースラインはブランチの解決後の HEAD に進みますが、保存されたパッチは元のベースラインとの差分です。そのため、このセッションでパッチ対象のファイルに触れるコミットを残していると、復元時の
git applyが失敗し、ストーリーは再びエスカレーションされます(これは意図的に明示的に行われます。オーケストレーターは、解決内容と古い試みを決して暗黙にマージしません)。解決作業に試みた変更がすでに含まれている、またはその変更に取って代わっている場合は、restore_patchを省略してください。コミットは再アーム後も再実行の開始点として残るため、最初からの再実行でそれらの上に直接構築できます。
試みた解釈が誤っていた場合(一般的なケース)は、restore_patch を完全に省略してください。オーケストレーターは、修正された意図に基づいて最初から再実行します。
特殊なケース:環境障害によるエスカレーション
コンテキスト内の env_fault_site が null ではない場合、実行が一時停止したのはストーリーではなく、環境の障害が原因です。[environment] プローブが失敗したか、検証コマンドが環境障害を宣言または検出した場所として、verify:<role>、probe:decision:<role>、probe:claim:<role>、probe:dispatch:<role> のいずれかが示されています。この試行は消費されていません。
probe:claim:<role> は、dev、fix、review、または workflow セッションが最終的な ## Auto Run Result に Environment fault: <what is broken> という行を書き込み、オーケストレーター自身のプローブがその後失敗したことを意味します。この行はプローブを起動しただけです。プローブで確認できなかった主張によって実行が一時停止することはないため、証拠となるのはセッションの記述ではなく、失敗したプローブです。paused_reason の session claim: 行には、その主張が引用されています。
- 仕様の変更は不要です。 障害を説明するために意図を明確化したり、ストーリーを解釈し直したりしないでください。
paused_reasonには、失敗したプローブまたはコマンドと、その出力の末尾が示されています。 - 人間には環境を修復するよう伝えてください(プローブが確認する停止中のサービス、コンテナー、エミュレーター、またはデータベースを起動するなど)。そのうえで、手動でプローブが通ることを確認してもらってください。
- その後、通常どおりエスカレーションを再アームします(環境を修復したことを記した解決記録を残します)。再アーム時に試行回数の上限はリセットされます。通常の再アームでは、ベースラインから dev セッションが再実行されます。試行の成果を保持する必要がある場合、人間は代わりにこのセッションを終了し、
bmad-loop resolve <run> --reverifyを実行できます。これにより、HEAD のツリー(そのまま、またはストーリー用に保持された worktree unit)を維持してその上で検証を再実行し、検証に通れば、dev セッションなしでレビューしてコミットします(unit はマージされます)。probe:dispatch:<role>による一時停止は、そもそもエスカレーションではありません。セッションは実行されていないため、人間は環境を修復してbmad-loop resume <run>を実行します(最初にプローブが再実行されます)。この一時停止に対してresolveを実行すると拒否されます。
絶対にしてはならないこと
- オーケストレーターの
result.jsonを書き換えないでください。これは dev/review の成果物であり、このセッションでは扱いません。 sprint-status.yamlを変更しないでください。また、仕様のstatus:フィールドも設定しないでください。オーケストレーターが再開時に仕様のステータスを決定論的に再アームします。仕様の内容のみ編集してください。tickets モードでは、tickets.py markを実行せず、プランのstatus、blocked_at、blocked_reasonも設定しないでください。オーケストレーターが独自のmarkでチケットを再アームし、これらの値をクリアします。- ストーリーを実装しないでください。機能コードの作成、テストの実行、コミットも行わないでください。作業は、修正済みの仕様と解決マーカーを残した時点で終了です。
spec_reaches_the_redriveがfalseの場合も同様です。再実行時に読み込まれる場所へ修正済みの仕様を反映するのは人間の作業です。redrive_base_refがブランチを示す場合は、そのブランチにコミットし、HEADを示す場合はメインチェックアウトに再適用します。これが必要であることと、どちらに当たるかを伝えてください。自分では行わないでください。 - スコープを広げないでください。エスカレーション対象の曖昧さだけを解消してください。無関係な問題に気づいた場合は人間に伝えますが、手を加えないでください。
Stories モード:センチネルと保存されたコピー
Stories モードでは、実際の仕様を書き始める前に開発セッションが矛盾や不足に直面し、計画すらできなかったストーリーは、凍結された仕様ではなく、固定スラッグのセンチネルファイルを残します。ファイル名は <id>-unresolved.md(意図が曖昧すぎて計画できなかった場合)または <id>-ambiguous.md(複数のストーリー仕様が ID に一致した場合)です。コンテキストの stories.sentinel ブロックには、そのファイル名と、セッションが記録した blocking_condition が記載されています。
センチネルは編集する仕様ではありません。内部に計画も <frozen-after-approval> ブロックもありません。そのため、センチネルの場合は次のようにします。
- 凍結された仕様を修正しようとしないでください(手順 4 の「凍結された仕様を編集する」は該当しません。仕様が存在しないためです)。代わりに、次の計画処理が成功するよう、_上流の_曖昧さを解消してください。通常は、人間と相談しながら
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がブランチを指定している場合、再駆動処理では新しいワークツリーを作成し、そのブランチのコミット済みツリーを基に再計画するため、未コミットの編集は認識されず、再計画で同じセンチネルが再び作成されます。そのブランチにコミットする必要があることを人間に伝えてください。HEADの場合は、メインのチェックアウトの作業ツリー内で再計画し、編集内容がそのまま読み込まれるため、コミットするよう伝えてはいけません。オーケストレーターは同じルールで再アームし、ブランチに編集内容が反映されるまで再開を保留します。- 再アーム時に、オーケストレーターはセンチネルを
ready-for-devに切り替えません(振り分ける計画がないためです)。センチネルのコピーを{run}/sentinels/<id>-<kind>.mdにパンくずとして保存し、センチネルを削除します。次回のディスパッチでは、ストーリーを最初から再計画します(spec_checkpointストーリーの場合は、レグ 1 からやり直します)。センチネルファイルを自分で操作しないでください。 - 人間が曖昧さの解消方法を決めたら、通常どおり解決マーカーを記述します。
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 に変更する必要があります)。一致するファイルがちょうど 1 つであれば、その仕様が再ディスパッチされます。一致するファイルが 0 個であれば、最初から再計画されます。その後、通常どおり解決マーカーを記述してください。再アームと再開の処理は、以降の手順を引き継ぎます。
解決できない場合
人間が対応を先送りする場合、必要な情報を実際に入手できない場合、または適切な修正が仕様の編集の範囲外にある場合(例:PRD/アーキテクチャの変更が必要な場合)は、その旨を明確に伝え、解決マーカーを記述しないでください。マーカーを記述せずに終了すると、ストーリーはエスカレーションされたままになり、実行は一時停止します。これが安全な既定の動作です。オーケストレーターは、解決が記録されていないストーリーを再アームしません。