Quick answer
Add a Notification hook to ~/.claude/settings.json. Claude Code runs the command when it needs your attention, and osascript shows a macOS notification. This is the example from the official Claude Code hooks guide:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
An empty matcher matches every notification type. If the file already has settings, add the hooks key to the existing object.
osascript sends notifications through Script Editor. If Script Editor has no notification permission, the command fails silently. Run osascript -e 'display notification "test"' once in Terminal, then open System Settings → Notifications → Script Editor and turn on Allow Notifications.Choose the right event
Claude Code has several hook events. Each one fires at a different moment, so pick the one that matches what you want to know.
| You want an alert when… | Hook event | Timing |
|---|---|---|
| Claude asks for permission to run a tool | PermissionRequest | At the moment Claude asks |
| A permission prompt is still waiting | Notification with matcher permission_prompt | After the prompt waits about six seconds |
| Claude is idle and waiting for your next message | Notification with matcher idle_prompt | About 60 seconds after Claude finishes, if you have not typed |
| Claude finishes each response | Stop | When the main agent finishes responding; not after you interrupt it |
This configuration combines them. It alerts when Claude asks for permission (with a sound), when Claude sits idle, and when a response ends:
{
"hooks": {
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs permission\" with title \"Claude Code\" sound name \"Glass\"'"
}
]
}
],
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code is waiting for you\" with title \"Claude Code\"'"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code finished responding\" with title \"Claude Code\"'"
}
]
}
]
}
}
Where to put the settings
| File | Applies to |
|---|---|
~/.claude/settings.json | All your projects |
.claude/settings.json | One project. You can commit it for your team. |
.claude/settings.local.json | One project, only on your machine. Git ignores it. |
- Claude Code normally picks up direct edits to settings files automatically.
- Type
/hooksin Claude Code to see the hooks it has loaded. This view is read-only. - Claude Code does not run hooks from any settings file, including your own, until you accept the workspace trust dialog for the folder.
Built-in notifications without hooks
Claude Code also has its own alert setting. In /config it is called Local notifications. In settings it is preferredNotifChannel. The values are auto, terminal_bell, iterm2, iterm2_with_bell, kitty, ghostty, and notifications_disabled.
{ "preferredNotifChannel": "terminal_bell" }
By default, Claude Code sends a desktop notification only in Ghostty, Kitty, and iTerm2. In other terminals, such as Apple Terminal, use a hook or the terminal bell. Turning notifications off does not stop your hooks from running.
Limits of a notification-only setup
- Each notification is one line of text. It does not show which of several sessions is waiting, unless you add that to the command.
- Clicking an
osascriptnotification usually opens Script Editor, not your terminal. - A
Stopalert means Claude stopped responding. It does not tell you whether the work is correct or the tests passed. - There is no history. When you run three sessions at once, you still have to find the one that stopped.
How MoriBlink handles Claude Code
MoriBlink is a native Mac app that tracks coding-agent sessions. Its Claude Code connection is a preview. When you approve a project in Settings → Projects → Claude Code, MoriBlink adds only its own command-hook groups to that project’s .claude/settings.local.json. Your other settings and hooks stay in place.
- Mori, the app’s character, appears on your current display for approval requests and questions. Click Mori to open the matching session.
- Recorded tool calls, failures, and observed timing appear in History, grouped by session and child agent.
- Passive capture leaves out prompts, transcripts, commands, file contents, and successful tool output.
- Claude Code hooks do not give a continuous live status. Live timers and completion alerts are not available for Claude Code sessions in the preview.
See every agent in one place
MoriBlink follows OpenCode, Claude Code, and Codex sessions on your Mac, alerts you when one needs you, and shows where a slow run spent its time.
Get early accessSources
- Claude Code hooks reference: events, matchers, settings files, workspace trust.
- Claude Code hooks guide: the notification example and the Script Editor permission note.
- Claude Code settings reference and terminal configuration:
preferredNotifChannel.
Checked against the official documentation on 26 October 2026. Claude Code changes often. Check /hooks after an update.
Questions
Why does my Claude Code notification hook not show anything?
Check three things. Give Script Editor notification permission in System Settings → Notifications, because osascript sends its notifications through Script Editor. Accept the workspace trust dialog, because Claude Code does not run hooks before you trust the folder. Then type /hooks to confirm that Claude Code loaded your hook.
How do I get notified only when Claude Code needs permission?
Use the PermissionRequest hook event. It runs at the moment Claude asks for permission. The Notification event with the permission_prompt matcher also works, but it runs only after the prompt has waited about six seconds.
Can Claude Code notify me when it finishes?
Yes. A Stop hook runs when the main agent finishes responding. It does not run when you interrupt Claude, and it does not tell you whether the work succeeded.