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 による通知が表示されるか確認します。

  1. スクリプトエディタ(Script Editor)を起動
  2. 新規スクリプトを作成して、以下を実行
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 通知で知ることができるようになりました。長時間のタスク実行中に別の作業ができるので、なかなか快適ですよ。

参考リンク