Long Claude Code tasks are only useful if you notice when they stop. There are two ways to get alerted without watching the terminal: a built-in terminal bell or notification, and hooks that run any command you like. Here are copy-paste setups for macOS and Linux.
Claude Code fires a Notification event when it is waiting for you, for example at a permission prompt or after it has finished and you haven't typed for a while. Add a hook to ~/.claude/settings.json. On macOS:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
On Linux, swap the command for notify-send:
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
The empty matcher fires for every notification type. Run /hooks inside Claude Code to confirm the hook is listed under Notification. Settings files and hook structure are covered in the settings.json guide.
Set matcher to one notification type to cut the noise:
| Matcher | Fires when |
|---|---|
permission_prompt | Claude needs you to approve a tool use, and the prompt has waited about six seconds (in a terminal) |
idle_prompt | Claude finished responding about 60 seconds ago and you haven't typed since |
The docs list further types for MCP elicitations, background sessions and usage-limit resumes; see the Notification section of the hooks reference.
idle_prompt waits about a minute. For an immediate alert, add a Stop hook, which runs whenever Claude finishes responding. Stop hooks don't take a matcher:
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code finished\" with title \"Claude Code\"'"
}
]
}
]
This sits next to Notification inside the same "hooks" object. Use notify-send on Linux. Keep the command exit code at 0: for Stop, exit code 2 makes Claude keep going instead of stopping.
Hooks receive JSON on stdin. For Notification, the text is in the message field. With jq installed, this script shows it (save as ~/.claude/notify.sh and chmod +x it):
#!/usr/bin/env bash
msg=$(jq -r '.message // "Needs your attention"')
if [ "$(uname)" = "Darwin" ]; then
osascript -e "display notification \"$msg\" with title \"Claude Code\""
else
notify-send "Claude Code" "$msg"
fi
exit 0
Then point the hook at it with "command": "~/.claude/notify.sh". Messages containing double quotes can break the AppleScript line, so treat this as a starting point.
For a sound on macOS, use a hook with afplay:
{
"hooks": {
"Notification": [
{ "hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Glass.aiff" }] }
]
}
}
Alternatively, no hook is needed for the terminal bell. By default Claude Code sends a desktop notification only in Ghostty, Kitty and iTerm2. In other terminals, add this to ~/.claude/settings.json:
{
"preferredNotifChannel": "terminal_bell"
}
osascript notifications go through Script Editor, and if it lacks permission the command fails without a prompt. Run osascript -e 'display notification "test"' once, then open System Settings > Notifications, find Script Editor and turn on Allow Notifications.notify-send needs a desktop notification daemon, so headless servers, SSH sessions and most containers won't show anything. Test it directly in a terminal first. If the command is missing, install libnotify-bin on Debian/Ubuntu or your distro's equivalent.set -g allow-passthrough on to ~/.tmux.conf so terminal notifications reach the outer terminal.Notifications are one of the simplest hooks. For blocking, formatting and secret-scanning examples, see 6 practical hook examples. To assemble and sanity-check hook JSON before pasting it into your settings, try the free hook builder. If you're unattended because you're running Claude Code on a schedule or in CI, the GitHub Actions guide is the better fit.
Keelwork bundles 10 workflow skills, 5 tested safety hooks (including a full guard-bash and a secret scanner), 3 subagents and 5 CLAUDE.md templates, with a one-command installer that safely merges into your settings.
Get Keelwork — $24 →