Claude Code の hooks の終了コード 0・2・その他の意味と使い分け

Claude Code 公開:

Claude Code の hooks スクリプトが返す終了コードによって、処理の続行・ブロック・警告がどう変わるかを解説します。終了コード 2 で標準エラー出力を Claude にフィードバックする仕組み、イベントごとの挙動の違い、JSON 出力による細かい制御を紹介します。

検証日 2026年9月7日 仕様変更が早い分野です。最新の公式ドキュメントも併せてご確認ください。
目次
  1. 終了コードの一覧
  2. イベントごとの「ブロック」の意味
  3. 使い分けの例
    1. PreToolUse で危険なコマンドを止める(2)
    2. PostToolUse で lint 失敗を Claude に直させる(2)
    3. 人間にだけ知らせる(1)
  4. JSON 出力で細かく制御する
  5. 関連する記事
  6. まとめ

hooks スクリプトの終了コードは、Claude Code に「続けてよいか」「止めるか」「注意だけするか」を伝える信号です。ここを理解していないと、lint が失敗しても Claude が気付かない、あるいは逆に警告のつもりが処理を止めてしまう、といった食い違いが起きます。

結論として、**0 は成功、2 はブロック(標準エラー出力が Claude に渡る)、それ以外は警告(ユーザーに表示、処理は続行)**です。

KEY POINT

この記事で分かること

  • 終了コード 0 / 2 / その他の挙動の違い
  • イベント(PreToolUse、PostToolUse など)ごとの「ブロック」の意味
  • JSON 出力による細かい制御

終了コードの一覧

終了コード扱い標準出力標準エラー出力
0成功ユーザーに表示される(一部のイベントでは Claude のコンテキストに追加)表示されない
2ブロック無視されるClaude に渡され、Claude はその内容に従って対応する
その他(1 など)非ブロックのエラー無視されるユーザーに表示される。処理は続行

「Claude に何かを伝えたい」ときは 2 を使います。「人間にだけ知らせたい」ときは 1 です。

イベントごとの「ブロック」の意味

終了コード 2 の効果は、どのイベントで返したかで変わります。

イベント終了コード 2 の効果
PreToolUseツールの実行を中止する。標準エラー出力の内容が Claude に渡る
PostToolUseツールは実行済み。標準エラー出力の内容が Claude に渡り、修正を促す
UserPromptSubmitプロンプトを Claude に渡さず、標準エラー出力の内容をユーザーに表示
Stop / SubagentStop停止を止め、Claude に作業を続けさせる(標準エラー出力が指示になる)
Notification効果なし(通知は既に発生している)
PreCompact効果なし

用語解説

PostToolUse で「ブロック」しても取り消せない: PostToolUse は実行後に走るため、ファイルは既に書き換わっています。2 を返す目的は「取り消し」ではなく、「lint エラーがあるから直して」と Claude に伝えることです。

使い分けの例

PreToolUse で危険なコマンドを止める(2)

#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf /|git push --force'; then
  echo "このコマンドは禁止されています: $cmd" >&2
  exit 2
fi
exit 0

PostToolUse で lint 失敗を Claude に直させる(2)

#!/usr/bin/env bash
file=$(jq -r '.tool_input.file_path // empty')
[[ "$file" == *.ts ]] || exit 0
if ! npx eslint "$file"; then
  echo "ESLint がエラーを報告しました。修正してください: $file" >&2
  exit 2
fi
exit 0

人間にだけ知らせる(1)

#!/usr/bin/env bash
file=$(jq -r '.tool_input.file_path // empty')
if [[ "$file" == */migrations/* ]]; then
  echo "注意: マイグレーションファイルが変更されました: $file" >&2
  exit 1
fi
exit 0

Claude の処理は止まらず、ユーザーの画面に警告だけが出ます。

JSON 出力で細かく制御する

終了コード 0 で、標準出力に JSON を書くと、より細かい制御ができます。

{
  "decision": "block",
  "reason": "テストファイルは実装フェーズでは変更できません"
}

decisionblock にすると終了コード 2 と同じくブロックされ、reason が Claude に渡ります。イベントによっては continue: false で Claude の処理全体を止めたり、追加のコンテキストを注入したりできます。対応するキーはイベントごとに異なるため、公式のリファレンスで確認してください。

標準出力に余計なものを出さない

JSON 制御を使う場合、標準出力に JSON 以外の文字列(デバッグ用の echo など)が混ざるとパースに失敗します。デバッグ出力は標準エラー出力に書いてください。

関連する記事

hooks の設定ファイルの書き方と、lint / format の自動実行の全体像は、親記事の hooks で lint と format を自動実行する を参照してください。

まとめ

  • 終了コード 0 は成功、2 はブロック(標準エラー出力が Claude に渡る)、その他は警告(ユーザーに表示)
  • PreToolUse の 2 は実行を中止、PostToolUse の 2 は実行済みの操作に対する修正指示になる
  • 人間にだけ知らせたいときは 1、Claude に直させたいときは 2
  • 標準出力の JSON で decisionreason を返すと細かい制御ができる

よくある質問

hooks で終了コード 1 を返すとどうなりますか?
0 と 2 以外の終了コードは「非ブロックのエラー」として扱われ、標準エラー出力がユーザーに表示されますが、Claude の処理は続行されます。
PostToolUse で終了コード 2 を返しても操作は取り消せますか?
取り消せません。PostToolUse はツール実行後に走るため、2 を返しても実行済みの操作は残ります。標準エラー出力の内容が Claude に渡され、修正を促す形になります。

参考にした一次情報

この記事は公式ドキュメントを基に AI が下書きを作成し、運営者が内容を確認して公開しています。誤りを見つけた場合はお問い合わせからお知らせください。