便利そうだなと思いつつ、やっと入門。。。
Claude Codeの作業に任意の処理を追加できるやつ(*´ω`*)
Claude Code Hooksとは
Claude Codeのライフサイクルの様々なポイントで実行されるユーザー定義のシェルコマンドです
らしい。
以下の例が紹介されている
- Notifications: 人間の承認などを待っているときの通知をカスタマイズ
- Automatic formatting: ファイル編集のたびにprettierなどのフォーマットを実行
- Logging: コンプライアンスまたはデバッグのために、実行された全コマンドの記録
- Feedback: 生成コードが規約に違反している場合、自動でフィードバック
- Custom permissions:: 運用ファイルまたは機密ディレクトリへの変更をブロック
注意
Hooksで設定したシェルコマンドは、ユーザ権限で実行されるので、注意が必要
ご利用は自己責任で、とのこと
設定
settings.jsonのhooksで設定する
/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:
Task、BashなどのToolを呼び出す前 - PostToolUse: Toolが完了した後
- Notification: 許可や入力待ちの通知時
- Stop: Claude Codeが応答を終了したとき。ユーザの割り込み停止は除く
- SubagentStop: サブエージェントが完了したとき
- PreCompact: 会話の要約(
compact)を実行したとき(manual、auto)
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のログも見れる
以上!! 思いの外、ボリュームがあったけど、いろいろできそう(*´ω`*)
とりあえず、フォーマットやテストからはじめてみよう〜