Claude Codeの/goal Stop hookが止まらない — 無限再発火の症状と回避策
/goalのStop hookが同じ理由で何十回も再発火する不具合の報告をまとめます。再発火する状況の型、止め方、条件文の書き換え例を扱います。
/goalを設定したセッションで、作業はもう終わっている(または止めたい)のに、Stop hookが「条件は未達」と返し続けることがあります。anthropics/claude-codeのissue #94041に、同じ症状が6件のコメント付きで集まっています。再発火は9回から約50回まで、ほぼ毎回「待っているだけ」の1行返信を生みます。
先に止め方を書きます。ユーザー側から/goal clearを打てば確実に終わります。モデルには解除する手段がありません。以降は、報告された状況の型、再発火を減らす条件文の書き方、似て見える正常動作との見分け方を順に扱います。
どんなときに再発火するのか
issueの本文とコメントを状況別に並べると、再発火の起点は大きく5つに分かれます。
| 状況 | 再発火の回数 | 起きていること |
|---|---|---|
| 圧縮(コンパクト)待ちの意図的な保留 | 再発火の回数9回以上 | 起きていること保留中でも同じ文面で未達を返す |
| 完了済みの項目を含む複数条件 | 再発火の回数21回以上 | 起きていること会話内で2度訂正しても、古い文面のまま |
| ユーザーの一時停止・取り消し・断念の指示 | 再発火の回数7回、24ターン、約50回 | 起きていること評価側が指示を認識したうえで、なお未達とする |
| 最後の項目がユーザー操作・日付・バックグラウンド作業の完了待ち | 再発火の回数9回(同一セッションで2度)、11回、7回 | 起きていること「正しく待っている」状態を表す判定がない |
| 13項目のうち4項目が「ユーザー待ちなら質問を記録」 | 再発火の回数12回連続 | 起きていること毎回違う理由で未達とされる |
環境はLinuxとmacOS、CLIとデスクトップアプリの両方です。バージョンは本文が2.1.258以降、コメントでは2.1.296や2.1.306も挙がっています。サブスクリプションとAPIキーのどちらでも起きており、モデルにも依存しないと報告されています。
再発火の1回は、1ターン分の課金になる
Stop hookが「未達」を返すと、Claudeは次のターンを始めます。ターンの中身が「まだ待っています」の1文でも、モデル呼び出しは1回走ります。
一時停止を頼んだ報告では、この点が最も皮肉な形で出ました。使用上限のリセットを待つための停止指示だったのに、再発火のたびに上限が減っていきます。別の報告では、同じ要約が再発火のたびに印刷され、ユーザーの手元に十数通の同じレポートが残りました。
原因はどこにあるのか
仕組みの側から見ると、/goalはセッション限定のプロンプト型Stop hookです。ターンが終わるたびに、条件と会話を小型の高速モデルへ渡し、判定を受け取ります。判定は3種類しかありません。
評価モデルが返せる3つの判定
未達(Not yet met)
Claudeが続行します。理由は次のターンの手がかりになります。
達成(Met)
ゴールが解除されます。
不可能(Impossible)
条件が満たせないと判断されたときに解除されます。
「条件は正しく、ただ待つしかない」を表す判定がありません。ユーザーの操作待ち、明日の時刻まで終わらない観測、動作中のバックグラウンドエージェントはどれも、未達にも不可能にも当てはまらない状態です。評価モデルは理由欄に「日付に縛られているだけで不可能ではない」と書きながら、未達を返し続けます。
原因の見立ては、報告者の間で分かれています。
- issue本文は、評価側が会話の最新の状態を読み直していない可能性を挙げます
- コメントの1つは、評価は会話を正しく読めており理由も正確で、足りないのは判定の種類だと述べます
後者の見立てでは、「完了済み」の訂正が効かない説明は付きません。両方の型が混在している、と考えるのが妥当です。いずれもissue上の仮説で、原因は確定していません。
最新のコメントは2026-10-21付けで、修正バージョンへの言及はありません。issueの状態はopenです。報告者の間では、第4の判定(ユーザー待ち・待機中の判定)を足す案が共通して出ています。
上限が働くと何が変わるか
再発火が無制限に続くわけではありません。Stop hookは、Claudeのツール呼び出しを挟まずに8回連続でブロックすると、Claude Code側が判断を上書きしてターンを終わらせます。/goalのページも、ツールを使わないターンが続くとループを止め、ゴールを設定したまま制御を返すと書いています。仕組みの詳細はCLAUDE_CODE_STOP_HOOK_BLOCK_CAPの解説にまとめています。
ただし、これは再発火の「終わり」であって「解決」ではありません。ゴールは残ったままなので、次のプロンプトで評価が再開し、同じ循環が始まります。issueも「上限が止めた後、別のターンで同じパターンが戻る」と報告しています。
デスクトップアプリで試した報告では、ゴールがアプリの終了・再起動を越えて残りました。再開したセッションの最初の返信で、Stop hookがもう一度発火しています。設定ファイルやhookファイルにゴールは書かれていないため、シェルから消す方法もありません。
今すぐできる止め方
ユーザーが/goal clearを打つ
確実に終わらせるには、ユーザーが/goal clearを実行します。stop / off / reset / none / cancelも同じ意味のエイリアスです。成功するとGoal cleared:に条件が続きます。
/goal clear注意点が2つあります。
- 引数なしの
/goalは状況表示だけで、解除はしません。デスクトップアプリの報告では、この表示にclearの案内が出ませんでした。モデルが「/goalを実行してください」と案内し、ユーザーが2度実行しても何も変わらなかった例があります - 「ゴールを取り消していい」「中断して」と会話で伝えても、評価モデルはそれを理由欄に書くだけで、ゴールは解除されません
リモートのセッションから止める手段がなかった報告
約50回再発火した報告では、断念を会話で伝えた後も、引数なしの/goalが状況表示しか出さず、リモートのセッションからは、ゴールを一時停止する明確な手段が無かったと報告されています。席を離れて回すゴールでは、手元から/goal clearを打てるかどうかが止める手段の分かれ目になります。
再発火を減らす条件文の書き方
起点の型が条件の最後の項目にあるなら、条件文の側で出口を作れます。
最後の項目を「待ち」で終わらせない
ユーザーの操作・日付・バックグラウンド作業の完了のどれかを最後の条件にすると、評価は未達しか返せません。ある報告者は、ユーザー待ちで終わる条件の書き方を避ける方法を挙げ、ただしそれを人が毎回守る前提は続かないとも述べています。
番兵(sentinel)文字列を出口にする
別の報告者は、条件文に「特定の接頭辞で始まる最終メッセージも達成とみなす」と書く回避策を共有しています。2.1.306で、評価が1ターンで達成を返したそうです。公式が定めた手段ではなく、同じ挙動が他のバージョンでも続く保証はありません。
ユーザー待ちを出口付きの条件にする
出口がない書き方
/goal 13項目のチェックが全て終わり、ユーザーに必要な質問を全て記録している評価は「質問を記録した」を確かめきれず、毎回違う理由で未達を返しました。
出口を明示した書き方
/goal 13項目のチェックが全て終わる。ただし、残りの作業がユーザーの操作待ちなら、
GOAL-BLOCKED: で始まる質問1通を最終メッセージに出せば達成とみなす例えばこの形にしておくと、待ちの状態が「達成」として扱われるため、ターンを終えられます。GOAL-BLOCKEDの部分は報告者が使った文字列で、任意の名前に置き換えられます。
打ち切りも条件に含める
「or 20ターン経過したら停止」のようにターン数の出口を足す方法は、/goalコマンドの解説でも扱っています。ただし、数えるのは会話を読む評価モデルです。厳密な回数制限ではなく、再発火を完全には防げません。
自作のStop hookならstop_hook_activeで抜ける
条件の評価を自分で書くなら、hookスクリプトの入力にあるstop_hook_activeがtrueのときに早期終了する書き方が公式の手引きにあります。prompt型の判定を自作する場合の考え方は、prompt hookでStopを判断させる記事に整理しています。同じ構造のループを意図的に回す例はralph loopプラグインです。
正常な待機と見分ける
バックグラウンド作業の待ちは、仕様として別の扱いがあります。再発火に見えても、次のような動作なら不具合ではありません。
| 見えるもの | 仕様上の動作 |
|---|---|
| サブエージェントやバックグラウンドのシェルが動いている間、評価が来ない | 仕様上の動作動作中のターンでは評価をスキップし、作業のないターンの終わりで評価する |
| 30分後に確認の通知が来る | 仕様上の動作初回のチェックインで、以降は1時間、2時間と間隔が延びる |
| アイドル中に勝手にターンが始まる | 仕様上の動作1回のプロンプトの間に最大3回まで。3回目で停止を告げる |
不具合の側は、バックグラウンド作業が無い(または終わった)のに、同じ理由の未達が連続する点で区別できます。バックグラウンドの待ちで再発火する報告では、評価が動作中の作業を認識しているのに未達を返しています。チェックインの間隔を変えるCLAUDE_CODE_GOAL_CHECKIN_MINUTESは、0で自動再試行も止まります。再発火の抑止を目的にした設定ではありません。
関連する未解決の報告
issue本文は、関連する報告を6件挙げています。
- 圧縮の境界で設定した
/goalが、ターンを始めない - バックグラウンドタスクが動いている間にStop hookがスキップされ、終了後に再評価されない
- 受け入れた「ブロックされた結果」の後も再発火する
- 評価側が
/goalに渡された指示を見られず、自分で不可能と宣言するまでループする
過去に閉じられた2件(stop_hook_active: trueでも再発火する報告、明示的な撤回を無視する報告)も含まれます。症状が近い場合は、issueの番号で検索すると報告をたどれます。
まとめ
再発火の根は、評価モデルに「正しく待っている」を表す判定がない点にあります。今できる対処は、ユーザーが/goal clearで解除すること、そして最後の項目を待ちで終わらせない条件文にすることです。修正バージョンの記載がないため、長時間の自走を任せるときは、解除の手段を手元に置いておく運用になります。