くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Claude Code Hooksに入門するためにガイドをちゃんと読んでみた

便利そうだなと思いつつ、やっと入門。。。
Claude Codeの作業に任意の処理を追加できるやつ(*´ω`*)

Claude Code Hooksとは

Claude Codeのライフサイクルの様々なポイントで実行されるユーザー定義のシェルコマンドです

らしい。

以下の例が紹介されている

  • Notifications: 人間の承認などを待っているときの通知をカスタマイズ
  • Automatic formatting: ファイル編集のたびにprettierなどのフォーマットを実行
  • Logging: コンプライアンスまたはデバッグのために、実行された全コマンドの記録
  • Feedback: 生成コードが規約に違反している場合、自動でフィードバック
  • Custom permissions:: 運用ファイルまたは機密ディレクトリへの変更をブロック

注意
Hooksで設定したシェルコマンドは、ユーザ権限で実行されるので、注意が必要
ご利用は自己責任で、とのこと

設定

settings.jsonhooksで設定する
/hooksコマンドで呼び出すこともできる

例: Bashツール実行前に、ログを出力する場合

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
          }
        ]
      }
    ]
  }
}

指定できるイベント

以下のタイミングで処理を差し込める

  • PreToolUse: TaskBashなどのToolを呼び出す前
  • PostToolUse: Toolが完了した後
  • Notification: 許可や入力待ちの通知時
  • Stop: Claude Codeが応答を終了したとき。ユーザの割り込み停止は除く
  • SubagentStop: サブエージェントが完了したとき
  • PreCompact: 会話の要約(compact)を実行したとき(manualauto)

hookの入力形式/Input

hookからのデータはJSONでコマンドに渡される
基本的にはこんな感じで、各イベントごとに内容が異なる

{
  // 共通のフィールド
  "session_id": "", // string
  "transcript_path": "", // string: 会話のJSONファイルのpath

  // Event-specific fields
  "hook_event_name": "" // string
  // ...
}

PreToolUse

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

PostToolUse

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Notification

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "Notification",
  "message": "Task completed successfully"
}

Stop & SubagentStop

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

PreCompact

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

hookの返り値/Output

hookの結果によって、処理をブロックするか、
ユーザに表示するフィードバックを伝えるかを制御できる

Exit Codeを返す

シンプルな方法はExit Codeを返すこと

  • 0: 成功。標準出力(stdout)はトランスクリプトモードでユーザに表示
  • 2: 拒否/ブロック。標準エラー(stderr)は、Claude Codeにフィードバックされ、自動で処理される
  • それ以外: ブロックしないエラー。標準エラー(stderr)は、ユーザに表示され、処理が続行する

Exit Code 2を返したときの振る舞いは、イベントによって異なる

  • PreToolUse: ブロックして、Claudeにエラーを表示
  • PostToolUse: Claudeにエラーを表示
  • Notification: 何もしない。ユーザにエラーを表示
  • Stop: Claude 停止を中断し、Claudeにエラーを表示
  • SubagentStop: 停止を中断し、Claudeのサブエージェントにエラーを表示
  • PreCompact: 何もしない。ユーザにエラーを表示

JSON形式で返す

標準出力(stdout)にJSONを出力すると、より細かい制御ができるっぽい

出力のJSON形式

{
  // 共通部分
  "continue": true, // hook実行後にClaudeが処理を続けるかどうか (default: true)
  "stopReason": "string", // continueがfalseのときに表示される理由のメッセージ
  "suppressOutput": true, // トランスクリプトモードから標準出力を非表示にする (default: false)

  // PreToolUseのみ
  "decision": "approve", // "approve" | "block" | undefined,
  "reason": "Explanation for decision",

  // PostToolUseのみ
  "decision": "block", // "block" | undefined,
  "reason": "Explanation for decision",

  // Stop / SubagentStopのみ
  "decision": "block", // "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}
  • すべての場合で、"continue": false"decision": "block"よりも優先される
  • stopReasonは、ユーザのみに表示され、Claudeにはフィードバックされない

Hookの実行について

  • Timeoutのデフォルトは60秒。コマンドごとに設定できる。タイムアウトは別のコマンドに影響しない
  • 一致するhookは、すべて並列に実行される
  • Claude Codeの環境でのカレントディレクトリで実行される
  • claude --debugで実行すると、Notificationのログも見れる

以上!! 思いの外、ボリュームがあったけど、いろいろできそう(*´ω`*)
とりあえず、フォーマットやテストからはじめてみよう〜