Here's the exact brief to reproduce it on another Mac.
1. Prerequisites
brew install terminal-notifier jq
which terminal-notifier # confirm the path
/opt/homebrew/bin/terminal-notifier is the Apple Silicon path. On an Intel Mac it's /usr/local/bin/terminal-notifier — substitute whatever which prints into both commands below.
2. Add the hooks
Open ~/.claude/settings.json (create it if missing) and merge in this hooks block:
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "m=$(jq -r '.message // \"Claude needs your attention\"'); /opt/homebrew/bin/terminal-notifier -title \"Claude Code\" -message \"$m\" -sound Ping -group claude-code -activate com.microsoft.VSCode 2>/dev/null || true"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "in=$(cat); t=$(printf '%s' \"$in\" | jq -r '.transcript_path // empty'); m=\"Done — ready for you\"; if [ -n \"$t\" ] && [ -f \"$t\" ]; then s=$(jq -rs '[.[] | select(.type==\"assistant\") | .message.content[]? | select(.type==\"text\") | .text] | last // empty' \"$t\" 2>/dev/null | tr '\\n' ' ' | sed 's/ */ /g' | cut -c1-140); [ -n \"$s\" ] && m=\"$s\"; fi; /opt/homebrew/bin/terminal-notifier -title \"Claude Code\" -message \"$m\" -sound Glass -group claude-code -activate com.microsoft.VSCode 2>/dev/null || true"
}
]
}
]
}
}
If the file already has other keys (env, permissions, theme…), add "hooks" alongside them — don't replace the file.
3. Grant notification permission
terminal-notifier -title "Claude Code" -message "test"
macOS will prompt once. Then System Settings → Notifications → terminal-notifier → Allow, and set the style to Alerts if you want them to stay on screen.
4. Reload
Restart Claude Code (hooks are read at session start). Verify with /hooks — both Stop and Notification should be listed.
Tweakables
| Field | What it does |
|---|---|
-activate com.microsoft.VSCode |
app focused on click — use com.apple.Terminal, com.googlecode.iterm2, or com.anthropic.claudefordesktop |
-sound Glass / Ping |
any name from /System/Library/Sounds |
-group claude-code |
shared group id — a new notification replaces the previous one instead of stacking |
cut -c1-140 |
body length cap |