Claude Code の Stop フックで作業完了をデスクトップ通知する設定
Claude が応答を終えた瞬間に通知を出す Stop フックの書き方を、macOS・Linux・Windows の 3 通りのコマンドで解説します。入力待ちを知らせる Notification フックとの使い分けと、終了コードの落とし穴も扱います。
長い作業を投げたあと、ターミナルを見張っているのは時間の無駄です。終わった瞬間に通知が来れば、その間は別の作業ができます。
Claude が応答を終えたタイミングで発火するのは Stop フックです。公式ドキュメントの入門で扱われている Notification フックは「入力待ち」を知らせるもので、目的が違います。この記事では両者を区別したうえで、3 つの OS それぞれの設定を示します。
KEY POINT
この記事で分かること
StopとNotificationの違いと、どちらを使うべきか- macOS・Linux・Windows それぞれの通知コマンドと設定例
- 終了コードの落とし穴(通知スクリプトで Claude が止まらなくなる)
Stop と Notification のどちらを使うか
名前が似ていますが、発火するタイミングが違います。
| イベント | 発火するとき | matcher |
|---|---|---|
Stop | Claude が応答を終えたとき | 非対応 |
SubagentStop | サブエージェントが終了したとき | エージェントの種類で指定できる |
Notification | Claude Code が通知を出すとき(権限確認、アイドルなど) | 通知の種類で指定できる |
「作業が終わったら知らせてほしい」なら Stop です。「権限の確認で止まっているのに気づきたい」なら Notification を使います。両方設定しても構いません。
Notification の matcher に指定できる種類には permission_prompt、idle_prompt、auth_success、agent_needs_input、agent_completed などがあります。指定できる値の一覧は hooks の matcher に書ける値一覧 にまとめています。
Stop に matcher を書いても無視される
Stop は matcher に対応していません。書いてもエラーにはならず、黙って無視されて毎回発火します。絞り込みたい場合は、フックのスクリプト側で判定してください。
設定例(OS 別)
~/.claude/settings.json に書きます。ファイルがなければ作成してください。
macOS
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"作業が完了しました\" with title \"Claude Code\"'"
}
]
}
]
}
}
通知が出ない場合は、osascript が経由する Script Editor に通知の権限がない可能性があります。公式ドキュメントは「Script Editor に通知権限がないとコマンドは黙って失敗し、macOS は権限を求めるプロンプトを出さない」と説明しています。ターミナルで次を 1 回実行して Script Editor を通知設定の一覧に出現させ、システム設定 > 通知で Script Editor の通知を許可してください。
osascript -e 'display notification "test"'
Linux
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' '作業が完了しました'"
}
]
}
]
}
}
notify-send はデスクトップ通知デーモンを必要とします。ヘッドレスサーバー、SSH セッション、多くのコンテナにはこれがありません。まず次のコマンドを直接実行して動作を確かめてください。コマンドが見つからない場合は、Debian と Ubuntu なら libnotify-bin パッケージを入れます。
notify-send 'Claude Code' 'test'
Windows(PowerShell)
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('作業が完了しました', 'Claude Code')\""
}
]
}
]
}
}
設定したら /hooks を実行すると、イベントごとのフックの一覧と、その定義元のファイルを確認できます。ただし /hooks のメニューは読み取り専用です。追加や変更は設定ファイルを直接編集するか、Claude に依頼してください。
終了コードの落とし穴
ここが Stop 固有の注意点です。Stop フックが終了コード 2 を返すと、Claude の停止がブロックされて会話が続きます。通知コマンドが失敗して 2 を返すと、意図せず Claude が動き続けることになります。
通知だけが目的なら、必ず 0 で終了させてください。
{
"type": "command",
"command": "notify-send 'Claude Code' '作業が完了しました' || true"
}
|| true を付けると、通知コマンドが失敗しても終了コードは 0 になります。
さらに、ブロックし続けた場合の上限もあります。公式ドキュメントによると、Claude Code は Stop フックが進展のないまま 8 回連続でブロックすると上書きします。意図的にブロックするフックを書く場合は、stdin の JSON の stop_hook_active を見て、すでに継続を引き起こしているなら早期に終了させます。
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Claude の停止を許可する
fi
# ここに本来の処理
終了コードの意味は hooks の終了コードの意味と使い分け にまとめています。
通知に中身を持たせる
Stop フックの stdin には、last_assistant_message(最後のアシスタントメッセージ)と stop_reason(停止の理由)が入ります。これを使うと、何が終わったのかを通知に出せます。
#!/usr/bin/env bash
# ~/.claude/hooks/notify-done.sh
INPUT=$(cat)
MSG=$(echo "$INPUT" | jq -r '.last_assistant_message // empty' | head -c 120)
notify-send 'Claude Code' "${MSG:-作業が完了しました}" || true
exit 0
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/notify-done.sh"
}
]
}
]
}
}
stdin の JSON の構造は hooks が受け取る stdin JSON の構造 に、フック全般の組み方は hooks で lint と format を自動実行する にまとめています。
用語解説
stop_reason: Claude が停止した理由を表す文字列です。通常のターン終了では end_turn が入ります。
まとめ
- 作業完了の通知は
Stop、入力待ちの通知はNotificationを使う Stopは matcher に対応していない。書いても黙って無視される- macOS は
osascript、Linux はnotify-send、Windows は PowerShell の MessageBox Stopフックが終了コード 2 を返すと停止がブロックされる。通知だけなら|| trueで 0 にする- 意図的にブロックするなら
stop_hook_activeを見て 8 回連続の上限を避ける last_assistant_messageを使うと、何が終わったのかを通知に含められる
よくある質問
- Stop フックと Notification フックはどう違いますか?
- Stop は Claude が応答を終えたときに発火します。Notification は権限確認や入力待ちなど、Claude Code が通知を出すときに発火します。「終わったら知らせてほしい」なら Stop です。
- Stop フックに matcher は書けますか?
- 書けません。Stop は matcher に対応しておらず、書いても黙って無視されます。毎回発火します。
- 通知スクリプトが原因で Claude が止まらなくなることはありますか?
- あります。Stop フックが終了コード 2 を返すと停止がブロックされ、会話が続きます。通知だけが目的なら必ず 0 で終了させてください。
- サブエージェントの完了も通知できますか?
- できます。SubagentStop フックを使います。こちらは matcher でエージェントの種類を指定できます。
参考にした一次情報
この記事は公式ドキュメントを基に AI が下書きを作成し、運営者が内容を確認して公開しています。誤りを見つけた場合は お問い合わせからお知らせください。