はいさい!しまぶだよ。
Claude Codeを使っていると、ツールの実行時に承認を求められることがあります。コードを書いている間は画面を見ているのでいいのですが、ちょっと席を外したり、別の作業(会議とか会議とか)をしたりしていると承認待ちになっていることに気付けません。それはとても悲しいことですし、かといってずっと画面に張り付いているわけにもいきません。
最初はSlackに通知を飛ばすことを考えたのですが、そこまで大げさにしなくてもいいのかなと。もっとカジュアルに自分だけが分かるものでいいんじゃないのかなと。
そこで、macOSのローカル通知で十分じゃないかと思いまして、色々と試した結果をメモしておきます。このあたりの通知周りはすでに何かベストプラクティスがあるような気がするのですが、せっかくなので。
最初に結論
terminal-notifier を使って、通知を表示しています。クリックするとターミナルがアクティブになるので、すぐに承認操作ができますし、アイコンもカスタム可能で便利です。
Claude CodeのHooks機能
調べてみると、Claude Codeにはhooks機能があり、特定のイベント時にスクリプトを実行できることがわかりました。
関連するイベントは以下の通りです。
PermissionRequest- Claudeが承認ダイアログを表示した時
Stop- Claudeが応答完了した時
Notification- Claudeが通知を送信した時
というわけで、今回はPermissionRequestを使ってみます。
hookに渡される情報
PermissionRequest時、JSON形式でstdinに情報が渡されます。
{
"tool_name": "Bash",
"tool_input": {
"command": "git commit -m \"...\""
}
}このtool_nameやtool_inputを使えば、どのツールで何をしようとしているのかを通知に表示できそうです。
hook設定
~/.claude/settings.json を編集します。
{
"hooks": {
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/notify-permission.sh"
}
]
}
]
}
}$CLAUDE_PROJECT_DIR はClaude Codeがhook実行時に提供する環境変数で、プロジェクトルート(Claude Codeを起動したディレクトリ)のパスに展開されます。
例えば /Users/yourname/projects/my-app で Claude Code を起動していれば、"$CLAUDE_PROJECT_DIR"/.claude/hooks/notify-permission.sh は /Users/yourname/projects/my-app/.claude/hooks/notify-permission.sh に展開されます。絶対パスをハードコードしなくて済むので便利です。
Environment variables - Claude Docs
スクリプトファイルの作成
設定ファイルで指定したパスにスクリプトを作成します。
指定したパスはプロジェクト直下の.claude/hooks/を指します。
# ディレクトリを作成
mkdir -p .claude/hooks
# スクリプトファイルを作成
touch .claude/hooks/notify-permission.sh
# 実行権限を付与
chmod +x .claude/hooks/notify-permission.sh以降、作成したファイル(notify-permission.sh)に処理を書いていきます。以下で紹介する通知方法のコードを参考にしてください。
通知方法いろいろ
macOSで通知を出す方法はいくつかあります。とりあえず、順番に試してみました。 osascriptを使う方法と、外部ツールを使う方法の2種類です。
以降で紹介するコードは、すべて notify-permission.sh に書く内容です。
osascript とは
osascript はmacOSに標準で搭載されているコマンドラインツールで、AppleScriptやその他のOSA(Open Scripting Architecture)言語スクリプトを実行できます。
Scripting with AppleScript - Apple Developer
ターミナルから -e オプションでスクリプトを直接実行できるので、シェルスクリプトからmacOSのGUI機能(通知、ダイアログ、アプリケーション操作など)を呼び出すのに便利です。
osascript -e 'display notification "Hello" with title "Test"'(これをターミナルで実行すると、通知が表示されます。便利だ。)
まずは、このosascriptを使って通知を出していきます。
1. display notification(バナー通知)
osascriptのdisplay notificationを使う方法です。数秒で自動的に消えて、通知センターに履歴が残ります。
基本形
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
osascript -e "display notification \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\""音を鳴らす
osascript -e "display notification \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\" sound name \"Glass\""※ sound name で指定したサウンドが鳴らない場合は afplay を使う方法もあります。
afplay /System/Library/Sounds/Glass.aiff &
osascript -e "display notification \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\""subtitle で詳細を表示
subtitle オプションを使うと、より詳細な情報を表示できます。
こんなイメージです。
タイトル: Claude Code
サブタイトル: Bash の承認を待っています
本文: cd ~/shimabox && git status最終形
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [ -n "$COMMAND" ]; then
DETAIL="$COMMAND"
elif [ -n "$FILE_PATH" ]; then
DETAIL="$FILE_PATH"
else
DETAIL=""
fi
osascript -e "display notification \"${DETAIL}\" with title \"Claude Code\" subtitle \"${TOOL_NAME} の承認を待っています\" sound name \"Glass\""
特徴
- 数秒で消える
- 通知センターに残る
- カスタムアイコン
- 不可(
display notificationにはアイコン指定オプションがない)
- 不可(
2. display alert(アラート通知)
osascriptのdisplay alertを使う方法です。クリックするまで消えません。
基本形
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
osascript -e "display alert \"Claude Code\" message \"${TOOL_NAME} の承認を待っています\""詳細メッセージ
display alert には subtitle がないので、message に改行で詳細を含めます。
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [ -n "$COMMAND" ]; then
DETAIL="$COMMAND"
elif [ -n "$FILE_PATH" ]; then
DETAIL="$FILE_PATH"
else
DETAIL=""
fi
osascript -e "display alert \"Claude Code\" message \"${TOOL_NAME} の承認を待っています\n${DETAIL}\" as critical"音を鳴らす
display alert には音のオプションがないので、afplay を併用します。
afplay /System/Library/Sounds/Glass.aiff &
osascript -e "display alert \"Claude Code\" message \"${TOOL_NAME} の承認を待っています\""特徴
- クリックするまで消えない
as critical/as warning/as informationalで種類を変えられる- 音を鳴らすには
afplayで対応可能 - カスタムアイコンは不可
※ as warningはmacOSのバージョンによって表示されない場合があります。as critical は確実に警告アイコンが表示されます。
3. display dialog(ダイアログ通知)
osascriptのdisplay dialogを使う方法です。こちらもクリックするまで消えませんが、カスタムアイコンが指定できます。
基本形
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
osascript -e "display dialog \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\" with icon caution"プリセットアイコン
3種類から選べます。
note- 吹き出し(情報)caution- 黄色の警告stop- 赤の停止
カスタムアイコン
任意の画像ファイルを指定できます。
osascript -e "set iconPath to POSIX file \"/path/to/icon.png\"" -e "display dialog \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\" with icon file iconPath"/path/to/icon.png は、"$CLAUDE_PROJECT_DIR/.claude/hooks/icon.png" のようにプロジェクト内のパスを指定するとよいです。
ボタンのカスタマイズ
デフォルトでは「OK」「キャンセル」の2つのボタンが表示されますが、buttons オプションで変更できます。
# OKボタンだけにする
osascript -e "display dialog \"承認を待っています\" with title \"Claude Code\" buttons {\"OK\"} default button \"OK\""音を鳴らす
display dialog にも音のオプションがないので、afplay を併用します。
afplay /System/Library/Sounds/Glass.aiff &
osascript -e "display dialog \"${TOOL_NAME} の承認を待っています\" with title \"Claude Code\" with icon caution"最終形
#!/bin/bash
# stdinからJSONを読み取る
INPUT=$(cat)
# tool_nameを取得
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
# tool_inputから詳細を取得
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 詳細メッセージを組み立て
if [ -n "$COMMAND" ]; then
DETAIL="$COMMAND"
elif [ -n "$FILE_PATH" ]; then
DETAIL="$FILE_PATH"
else
DETAIL=""
fi
# 音を鳴らしてダイアログを表示(OKボタンのみ、カスタムアイコン)
afplay /System/Library/Sounds/Glass.aiff &
osascript -e "set iconPath to POSIX file \"/path/to/icon.png\"" \
-e "display dialog \"${TOOL_NAME} の承認を待っています\n${DETAIL}\" with title \"Claude Code\" with icon file iconPath buttons {\"OK\"} default button \"OK\""特徴
- クリックするまで消えない
- カスタムアイコン
- 可能
- これはちょっとうれしいかも
- ボタンのカスタマイズ
- 可能
- 音
afplayで対応可能
4. terminal-notifier(外部ツール)
terminal-notifier を使う方法です。カスタムアイコン、クリックアクション、タイムアウトなど柔軟な設定が可能です。
terminal-notifier とは
macOSの通知センターにコマンドラインから通知を送るためのオープンソースツールです。
- リポジトリ
- Homebrew公式
広く使われており、通知を送るだけのシンプルなツールなので安心して使えるかと思います。
インストール
brew install terminal-notifier基本形
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
terminal-notifier -title "Claude Code" -message "${TOOL_NAME} の承認を待っています" -sound Glassクリックでターミナルをアクティブに
通知をクリックすると、Claude Codeが動いているターミナルを前面に持ってきて、すぐに承認操作ができます。これが地味に便利。
terminal-notifier -title "Claude Code" -message "${TOOL_NAME} の承認を待っています" -execute "osascript -e 'tell application \"Ghostty\" to activate'"ターミナルは人それぞれですから、以下のような感じでターミナルアプリに応じて変更してください。
| ターミナル | コマンド |
|---|---|
| Ghostty | osascript -e 'tell application "Ghostty" to activate' |
| iTerm | osascript -e 'tell application "iTerm" to activate' |
| Terminal.app | osascript -e 'tell application "Terminal" to activate' |
すべてを試したわけではないです!
詳細情報も表示
-subtitle オプションを使うと、より詳細な通知が可能です。
タイトル: Claude Code
サブタイトル: Bash の承認を待っています
メッセージ: cd ~/shimabox && git commit -m "test"最終形
#!/bin/bash
# stdinからJSONを読み取る
INPUT=$(cat)
# tool_nameを取得
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
# tool_inputから詳細を取得
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 詳細メッセージを組み立て
if [ -n "$COMMAND" ]; then
DETAIL="$COMMAND"
elif [ -n "$FILE_PATH" ]; then
DETAIL="$FILE_PATH"
else
DETAIL=""
fi
# terminal-notifier で通知(クリックでターミナルをアクティブに)
terminal-notifier -title "Claude Code" -subtitle "${TOOL_NAME} の承認を待っています" -message "$DETAIL" -sound Glass -contentImage "/path/to/icon.png" -execute "osascript -e 'tell application \"Ghostty\" to activate'"初回実行時に通知許可を求められます。システム設定 → 通知 → terminal-notifier で許可が必要です。
osascript系との比較
| 機能 | osascript系 | terminal-notifier |
|---|---|---|
| カスタムアイコン | dialog のみ | ○ |
| 音 | ○(notification は標準、他はafplayと併用する) | ○ |
| クリック時にURL開く | × | ○ (-open) |
| クリック時にコマンド実行 | × | ○ (-execute) |
| タイムアウト設定 | × | ○ (-timeout) |
| 通知センターに残る | notification のみ | ○ |
使えるサウンド一覧
/System/Library/Sounds/ にあるファイルが使えます。
- Glass, Ping, Pop, Purr, Submarine
- Blow, Bottle, Frog, Funk, Hero
- Morse, Sosumi, Tink, Basso
あと、自分で好きな音も選べるかと思います。
通知方法の比較まとめ
| 方法 | 消えない | 音 | カスタムアイコン | モーダル |
|---|---|---|---|---|
| display notification | × | ○ | × | × |
| display alert | ○ | △(afplay) | × | ○ |
| display dialog | ○ | △(afplay) | ○ | ○ |
| terminal-notifier | ○ | ○ | ○ | × |
個人的には、display dialog も使えるかなと思いましたが、terminal-notifier が一番使い勝手がよいかなと思っています。通知をクリックしてターミナルに戻れたりするのがよいです。
あと、細かい設定もしやすいのかなと思います。作業中で通知がわずらしい場合は通知をそもそもオフにしたりできますし。
断念したこと 😢
Automatorアプリや AppleScript アプリを作成してカスタムアイコンでの通知を出す方法も試したのですが、hookからアプリに引数(tool_name)を渡す方法がうまくいかず断念しました。
display dialog の with icon file または terminal-notifier の -contentImage でカスタムアイコンを指定する方が簡単でした。
おわりに
Claude Codeのhooks機能を使って、承認待ちの通知をmacOSに飛ばす方法を試してみました。
個人的にはterminal-notifier, terminal-notifier + クリックでターミナルアクティブ化 の組み合わせがけっこう良いかと思っています(色々とカスタムできそうですし)。これで安心して別の作業ができる。めでたしめでたし。
他にもいいやり方はもちろんあると思いますが、まず自分が試してみた結果をまとめてみました。
自分で手を動かすのはやっぱ大事だよねって。そこで、他にいい方法があれば試せばいいのだし。
(自分で考えた?設定は愛着が湧くし??)
というわけで、他にいい方法があればぜひ教えてください。
それでは。








