Claude Code Hooksとは
Claude Code Hooksは、Claude Codeの動作に応じて特定のアクションを実行できる機能です。例えば、エージェントが応答を完了したときや、ツール実行の前後などのイベントをトリガーとして、スクリプトやコマンドを自動実行できます。
Claude Code HooksでmacOS通知
今回は、Claude Codeのタスクが完了したときにmacOSの通知を表示する方法を紹介します。
↓下の画像が実際のClaude Codeの画面上のメッセージです。
もともとはこの記事を参考にしつつ、通知内容をより詳細に改善した実装になります。
実装のポイント
-
STOP
イベントをトリガーとして使用 -
notify-end.sh
スクリプトで transcript_path から最新のアシスタントメッセージを取得 - macOSの通知には
osascript
を利用して音付きで通知
STOPイベントについて
公式ドキュメントによると:
STOP
Runs when the main Claude Code agent has finished responding. Does not run if the stoppage occurred due to a user interrupt.
Claude Code agentが応答を完了したときに実行されます(ユーザーによる中断では実行されません)。
入力データの形式
STOPイベントで受け取るInputは以下のような形式です:
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"hook_event_name": "Stop",
"stop_hook_active": true
}
デバッグ用のhook設定
実際に呼び出されるときの入力データを確認したい場合は、以下のようなhookを設定してファイルに出力できます:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c -r '.' >> ~/.claude/stop-log.txt"
}
]
}
]
}
}
transcript_pathの内容
transcript_pathには、セッションでのやり取りがJSONL形式で保存されています。
例:
{
"parentUuid":"d9d1234a-f73f-4460-b1eb-14a8e844df3d",
"isSidechain":false,
"userType":"external",
"cwd":"/Users/m.naka/repos/nakamasato/github-actions",
"sessionId":"b0004de5-676b-4ecb-a49e-23d02a39bfb8",
"version":"1.0.44",
"type":"user",
"message":{
"role":"user",
"content":[
{
"tool_use_id":"toolu_01A7e58yKYcYTYeVYJ8NgAJk",
"type":"tool_result",
"content":"Based on the GitHub releases page, the latest version of ruff-pre-commit is v0.12.2, released on 03 Jul."
}
]
},
"uuid":"f67a28e2-2bce-45f0-8545-3450a9663707",
"timestamp":"2025-07-11T11:06:58.102Z",
"toolUseResult":{
"bytes":293809,
"code":200,
"codeText":"OK",
"result":"Based on the GitHub releases page, the latest version of ruff-pre-commit is v0.12.2, released on 03 Jul.",
"durationMs":3079,
"url":"https://github.com/astral-sh/ruff-pre-commit/releases"
}
}
message.role
フィールドを確認すると、user
または assistant
の値が設定されています。エージェントが完了したときの最後のメッセージを取得するため、role
が assistant
の最新エントリを抽出して通知に表示することにしました。
通知スクリプトの実装
今回は複数の処理が必要なので、シェルスクリプトとして実装します。
#!/bin/bash
# 標準入力からhookのInputデータを読み取り
INPUT=$(cat)
# 現在のセッションディレクトリ名を取得(hooksはsessionと同じディレクトリで実行される)
SESSION_DIR=$(basename "$(pwd)")
# transcript_pathを抽出
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path')
# transcript_pathが存在する場合、最新のassistantメッセージを取得
if [ -f "$TRANSCRIPT_PATH" ]; then
# 最後の10行から assistant のメッセージを抽出し、最新のもの(最後)を取得
# 改行を削除して60文字に制限
MSG=$(tail -10 "$TRANSCRIPT_PATH" | \
jq -r 'select(.message.role == "assistant") | .message.content[0].text' | \
tail -1 | \
tr '\n' ' ' | \
cut -c1-60)
# メッセージが取得できない場合のフォールバック
MSG=${MSG:-"Task completed"}
else
MSG="Task completed"
fi
# osascriptでmacOS通知を表示(音付き)
osascript -e "display notification \"$MSG\" with title \"ClaudeCode ($SESSION_DIR) Task Done\" sound name \"Glass\""
スクリプトの動作説明
-
セッション情報の取得:
pwd
でhookが実行されているディレクトリを取得し、セッション名として利用 -
メッセージ抽出: transcript_path の最後の10行から
role
がassistant
のメッセージを抽出し、最新のものを取得 -
通知表示:
osascript
を使って、効果音("Glass")とともに通知を表示
これにより、エージェントが完了すると通知音とともに、どのセッションで何が終わったのかが右上の通知領域で確認できるようになります。
hooks設定ファイル
上記のスクリプトを動作させるには、以下のような設定を ~/.claude/hooks.json
に追加します:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/scripts/notify-end.sh"
}
]
}
]
}
}
まとめ
Claude Code Hooksを使うことで、エージェントのタスク完了を見逃すことなく、効率的に作業を進められるようになります。特にバックグラウンドで長時間実行されるタスクがある場合に重宝する機能です。
ただし、毎回細かくなるのは逆にうざいので、エージェントタスク完了にある程度の時間がかかった場合のみ通知するなどしたほうがいいかもなと思いました。