TL;DR: Claude Code が入力待ちになったとき、macOS のデスクトップ通知と音声読み上げで知らせるフック(hook)を設定する方法。SAY!!
背景
Claude Code はそこそこ長い時間タスクを実行することがあるので、完了したら通知してほしいですよね。
公式の通知設定もあるんですが、通知が鳴らなかったり気付かなかったりすることがあります。
ということで、カスタムフック(hook)を使って macOS のデスクトップ通知+音声読み上げで確実に気付けるようにしましょう。
ターミナルのネイティブ通知も試す価値あり
フックを設定する前に、お使いのターミナルがネイティブ通知に対応しているか確認してみてください。
- Kitty / Ghostty — 設定不要でネイティブ通知が動作します
- iTerm2 — Settings → Profiles → Terminal で「Notification Center Alerts」を有効にし、「Send escape sequence-generated alerts」にチェック
- tmux 内 —
set -g allow-passthrough onを有効にすれば、外側のターミナル(iTerm2, Kitty, Ghostty)に通知が届きます
これで十分ならフック設定は不要です。もっとカスタマイズしたい場合は読み進めてください。
前準備: スクリプトエディタの通知を有効にする
まず、osascript による通知が表示されるか確認します。
- スクリプトエディタ(Script Editor)を起動
- 新規スクリプトを作成して、以下を実行
display notification "test notification" with title "test title" subtitle "test subtitle" sound name "Glass"
音は鳴るけど通知が出てこない場合は、システム設定 > 通知 から「スクリプトエディタ」を探して通知を有効にしてください。
フックスクリプトの作成
~/.claude/scripts/hooks/notification/desktop-notification.sh を作成します。
スクリプトはフックの stdin から渡される JSON をパースするために jq を使います。インストールしていない場合は事前に入れておいてください。
brew install jq
#!/usr/bin/env bash
#
# 入力待ち通知 macOS専用
#
PROJECT=$(basename "$(pwd)")
# フックの stdin から JSON を読み取り、メッセージを抽出する
if [ ! -t 0 ] || [ -p /dev/stdin ]; then
INPUT=$(cat -)
# jq が使えれば JSON から .message を取得、なければそのまま使う
if command -v jq > /dev/null 2>&1; then
MESSAGE=$(echo "$INPUT" | jq -r '.message // empty' 2>/dev/null)
fi
MESSAGE=${MESSAGE:-"次の指示を待っています"}
else
MESSAGE=${1:-"次の指示を待っています"}
fi
osascript -e "display notification \"$MESSAGE\" with title \"Claude Code: $PROJECT\" sound name \"Pluck\""
if echo "$MESSAGE" | grep -qE '^[a-zA-Z0-9!\\?: ]+$'; then
# 英字のみメッセージ
say -v "Samantha (Enhanced)" "$MESSAGE" || say -v "Samantha" "$MESSAGE" || true
else
# 設定 > 読み上げコンテンツ > システムの声 で音声を変更
say "$MESSAGE" || true
fi
作成したら実行権限を付けます。
chmod +x ~/.claude/scripts/hooks/notification/desktop-notification.sh
ポイントをいくつか:
- フックの stdin には JSON が渡されるので、
jqでメッセージを取り出している PROJECTにカレントディレクトリ名を入れて、どのプロジェクトからの通知かわかるようにしているsayコマンドで音声読み上げもするので、画面を見ていなくても気付ける- 英語メッセージと日本語メッセージで読み上げ音声を切り替えている
Claude Code の設定
~/.claude/settings.json にフックを登録します。入力待ち通知には専用の Notification イベントを使います。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/hooks/notification/desktop-notification.sh"
}
]
}
]
}
}
Notification イベントは Claude がユーザーの入力を待つタイミングで発火するので、これだけで十分です。スクリプト側で stdin の JSON を受け取ってメッセージを取り出します。
API エラー(レート制限など)でも通知が欲しい場合は、StopFailure イベントも追加するとよいです。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/hooks/notification/desktop-notification.sh"
}
]
}
],
"StopFailure": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/hooks/notification/desktop-notification.sh 'エラーが発生しました'"
}
]
}
]
}
}
CLAUDE.md に書く方法(簡易版)
フックを設定するのが面倒なら、~/.claude/CLAUDE.md に直接書く方法もあります。
## ユーザー入力待ちの時、タスクが完了した時に通知する
入力を待機しているかタスクが完了しているかに関係なく、Claude コードの実行が終了するたびにユーザー通知する。
通知には以下のコマンドラインを使用。
\```
osascript -e 'display notification "次の指示を待っています" with title "Claude Code" sound name "Pluck"'
\```
ただし、この方法はコンテキスト任せなので通知されないこともあります。確実に通知したいならフックの方がおすすめです。
まとめ
以上のような感じで、Claude Code の入力待ちを macOS 通知で知ることができるようになりました。長時間のタスク実行中に別の作業ができるので、なかなか快適ですよ。