When Claude Code needs your attention — whether it’s waiting on a permission request, finished a long task, or just has something to tell you — it’s easy to miss if you’ve switched to another window. Here’s how to wire up native macOS notifications so you never have to babysit the terminal again.
The notification script
Save this script to ~/.claude/notify.sh:
#!/bin/bash
TITLE="$1"
MESSAGE="$2"
# Check env var first (works if Claude was launched from the shell directly)
if [ "$TERM_PROGRAM" = "vscode" ]; then
APP="com.microsoft.VSCode"
elif [ "$TERM_PROGRAM" = "WezTerm" ]; then
APP="com.github.wez.wezterm"
elif [ "$TERM_PROGRAM" = "iTerm.app" ]; then
APP="com.googlecode.iterm2"
else
# Walk up the full ancestor chain, not just $PPID
APP="com.apple.Terminal" # default
PID=$$
for _ in $(seq 1 10); do
PID=$(ps -p "$PID" -o ppid= 2>/dev/null | tr -d ' ')
[ -z "$PID" ] || [ "$PID" -le 1 ] && break
PROC=$(ps -p "$PID" -o comm= 2>/dev/null | xargs basename 2>/dev/null)
case "$PROC" in
*Code*) APP="com.microsoft.VSCode"; break ;;
*wezterm*) APP="com.github.wez.wezterm"; break ;;
*iTerm*) APP="com.googlecode.iterm2"; break ;;
*Warp*) APP="dev.warp.Warp-Stable"; break ;;
*Alacritty*) APP="io.alacritty"; break ;;
*kitty*) APP="net.kovidgoyal.kitty"; break ;;
esac
done
fi
terminal-notifier -title "$TITLE" -message "$MESSAGE" -activate "$APP"
The script detects which terminal emulator launched Claude Code — first by checking $TERM_PROGRAM, then by walking up the process ancestry — so that clicking a notification focuses the right app. Make it executable:
chmod +x ~/.claude/notify.sh
You’ll also need terminal-notifier◹ if you don’t have it:
brew install terminal-notifier
Hooking into Claude Code events
Add the following to your ~/.claude/settings.json under the hooks key:
"hooks": {
"PermissionRequest": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash $HOME/.claude/notify.sh \"🔔 Claude Code\" \"Claude needs your input\""
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash $HOME/.claude/notify.sh \"🔔 Claude Code\" \"Claude needs your attention\""
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash $HOME/.claude/notify.sh \"✅ Claude Code\" \"Task completed\""
}
]
}
]
}
Three events are covered: PermissionRequest fires when Claude is blocked waiting for you to approve a tool call, Notification catches any other attention-needed signal, and Stop lets you know when the task is fully done. Now you can freely switch away while Claude works and get a tap on the shoulder the moment something needs you.