Claude Codeには、メインのエージェントが応答を終了したときに実行されるStop hookがあります。
応答を終了したときに発火するので、以下のような使い方ができます。
- デスクトップ通知
- フォーマッターやリンターを最後に実行する
- クリーンアップ
- テストや型チェックが通るまで実行を続けさせる
- 変更した内容をコミットさせる
ただ、実行を続けさせると無限ループになり、終わらないのではないかと気になると思います。
この記事では無限ループを防ぐClaude Codeの機能を紹介します。
stop_hook_activeフィールド
Stop hookでdecision: "block"を返してClaudeが応答を継続するとき、再度Stop hookが呼ばれる際の入力JSONにstop_hook_activeというフィールドが含まれます。
{
"stop_hook_active": false,
// 略...
}
stop_hook_activeは、「Stop hookによってすでに継続が要求されている状態か」を表すフラグになっており、hookスクリプトの先頭でこの値をチェックして、trueなら早期exitするようにすることで、無限ループを防ぐことができます。
#!/usr/bin/env bash
INPUT="$(cat)"
if [ "$(echo "${INPUT}" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fi
# 略...
CLAUDE_CODE_STOP_HOOK_BLOCK_CAP 環境変数
実はClaude Code側でも無限ループにならないように上限が設けられています。
(何もしてなくても無限ループにならんのかい)
デフォルトでは、Stop hookが連続8回ブロックすると、それ以降のブロックは無視されてClaudeが止まるようになっています。
この上限を変更したい場合に使うのが、CLAUDE_CODE_STOP_HOOK_BLOCK_CAP環境変数です。
ただ、トークンの無駄遣いになるだけだと思うので、stop_hook_activeフィールドや別の手段で早期exitするようにするのが良いと思います。
さいごに
Stop hookで継続させるロジックを書くときは、stop_hook_activeのチェックを定型として入れておくのが簡単なのでおすすめです。
(Claudeが期待していることを終わらせるまでの場合は使えないですが)