Guides

Get notified when Claude Code finishes or needs you

Claude Code already sends a desktop notification in iTerm2, Ghostty and Kitty when it finishes a task or waits for your permission and you seem to be away. In Apple’s Terminal, Warp or the VS Code terminal you turn it on yourself: one setting rings the terminal bell, and a Notification hook can run any command, from a sound to a banner.

The short answer

Where you use Claude CodeWhat to do
Ghostty or KittyNothing. Notifications reach the macOS Notification Center on their own.
iTerm2In Settings → Profiles → Terminal, check “Notification Center Alerts”, click “Filter Alerts” and turn on “Send escape sequence-generated alerts”.
Terminal, Warp, VS Code, CursorSet "preferredNotifChannel": "terminal_bell", or add a Notification hook.
Inside tmuxAdd set -g allow-passthrough on to ~/.tmux.conf, or the alert never leaves tmux.
Claude DesktopNothing. It notifies you when a session finishes and you aren’t looking at it.
Your phoneStart Remote Control and turn on push notifications in /config.

When Claude Code notifies you, and when it doesn’t

Claude Code’s alerts are late on purpose: they’re meant for when you’ve looked away. In a terminal session:

So if you sit at the terminal typing, you won’t hear a thing, and if you step away, the “finished” alert comes a minute late. For a signal the moment something happens, hook the Stop and PermissionRequest events instead.

Turn on the terminal bell

The simplest option works in any terminal. Run /config in Claude Code and change Local notifications, or add this line to your settings:

~/.claude/settings.json

{
  "preferredNotifChannel": "terminal_bell"
}

The other values are auto (the default), iterm2, iterm2_with_bell, kitty, ghostty and notifications_disabled. In Apple’s Terminal, Claude Code’s first-run setup may have turned the audible bell off. If the bell stays silent, turn it back on in Terminal’s Settings → Profiles → Advanced → “Audible bell”.

A desktop banner or a sound with a hook

Hooks are commands that Claude Code runs at fixed points in a session. A Notification hook runs whenever Claude Code would notify you, in any terminal, next to the built-in alert. This one shows a macOS banner:

~/.claude/settings.json

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

If your settings already have a "hooks" object, add "Notification" inside it next to the other events rather than replacing it. Type /hooks in Claude Code to check that the hook is listed.

No banner? osascript shows its banners through the Script Editor app. If Script Editor has no permission to send notifications, the command fails silently and macOS doesn’t ask. Run osascript -e 'display notification "test"' in a terminal first, and if nothing appears, allow Script Editor in System Settings → Notifications.

For a sound instead of a banner, play one of the system sounds in /System/Library/Sounds:

"command": "afplay /System/Library/Sounds/Glass.aiff"

Which event to use for which moment

The matcher of a Notification hook picks the notification type. Two other events fire with no delay at all.

MomentEvent and matcherWhen it fires
Claude asks for permissionNotification, permission_promptAfter about six seconds without typing
Claude asks for permission, right awayPermissionRequestImmediately. Keep the hook silent: a hook that prints a decision approves or denies for you
Claude finished and you’re awayNotification, idle_promptAbout 60 seconds after the last response
Claude finished a responseStopImmediately, after every response, so it can get noisy
An MCP server asks you to fill in a formNotification, elicitation_dialogAfter about six seconds without typing

Separate matchers can play different sounds, so you can tell “it needs me” from “it’s done” without looking:

~/.claude/settings.json

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Ping.aiff" }]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Tink.aiff" }]
      }
    ]
  }
}

Several sessions at once

With three or four sessions open, “Claude Code needs your attention” doesn’t say which one. Every hook gets a JSON object on standard input with the session’s folder in cwd, the alert text in message and the type in notification_type. This script puts the folder name in the banner’s title:

~/.claude/hooks/notify.sh

#!/bin/bash
# Shows which project needs you, and why
input=$(cat)
project=$(basename "$(jq -r '.cwd' <<<"$input")")
message=$(jq -r '.message // "Needs your attention"' <<<"$input")
osascript -e 'on run argv' \
  -e 'display notification (item 1 of argv) with title (item 2 of argv)' \
  -e 'end run' "$message" "Claude Code · $project"

Make it executable with chmod +x ~/.claude/hooks/notify.sh and point the hook at it with "command": "\"$HOME\"/.claude/hooks/notify.sh". Passing the text as arguments keeps quotes in a message from breaking the AppleScript. The script needs jq; if which jq prints nothing, install it with Homebrew.

For naming, isolating and watching several sessions, see running several Claude Code sessions without losing track.

Some terminals can also show each session’s state themselves (working, waiting on you or done) through the Program Status Protocol, OSC 7501. Claude Code 2.1.295 and later reports it with nothing to turn on; your terminal’s documentation says whether and where it shows it.

Keep alerts from breaking your focus

An alert for every finished response trains you to switch windows and check. In threads where developers compare setups, that checking comes up again and again as what breaks concentration. One developer called alt-tabbing to check on Claude “such a flow killer”. A few habits help:

What to do with the waits themselves is a guide of its own: what to do while Claude Code is working.

On your phone

With Remote Control on (/remote-control in a session, or claude --remote-control), Claude Code can push to the Claude app on your phone. Allow notifications for the app, then in /config turn on Push when Claude decides, for long tasks that finish or a decision Claude needs, and Push when actions required, for permission prompts and questions. You can also ask for one in the prompt, for example “notify me when the tests finish”.

In Claude Desktop

The Code tab sends a macOS notification when a session finishes a task and you aren’t viewing it. Hooks from ~/.claude/settings.json run there too, with one difference: permission_prompt fires about six seconds after Claude asks, whether or not you’re typing.

A quieter option: Meowdoro

Other apps show agent status in the notch too; we compared them in notch apps for AI coding agents. We make Meowdoro, so read this part as a disclosure as much as a suggestion. It’s a focus timer that lives around the MacBook notch and connects to Claude Code, in a terminal or in Claude Desktop, and to Codex through each agent’s own plugin system. Every session shows in a small black island as working, finished, failed or waiting for you, with the question or permission it’s waiting on, and a click takes you to it.

During a focus round, anything that needs you slides out as one silent line for four seconds, or waits until you peek. During a break nothing about agents shows at all, and when the next focus starts, one line says what happened while you rested. Its hooks only listen: they never approve a permission or answer an agent. It’s free before December 2026, then a one-time $20 for one Mac, on macOS 14 or later. How the island shows agents · focus without interruptions.

Questions

Can Claude Code play a sound when it’s done?

Yes. Set preferredNotifChannel to terminal_bell for the terminal’s bell, or add a Notification hook with the idle_prompt matcher, or a Stop hook, that runs afplay with a sound from /System/Library/Sounds.

Why don’t I get notifications in the VS Code terminal?

By default Claude Code sends desktop notifications only in Ghostty, Kitty and iTerm2. In VS Code, Cursor or Warp, use a Notification hook or the terminal bell.

How do I get notified only when Claude needs permission?

Give the Notification hook the matcher permission_prompt. For an alert the instant Claude asks, use a PermissionRequest hook that only plays a sound and prints nothing.

Do notifications work over SSH?

Yes, in Ghostty, Kitty and iTerm2: the desktop notification travels back over SSH to your Mac. In iTerm2, turn on forwarding as in the table above. A hook runs on the machine where Claude Code runs, so osascript there only works when that machine is a Mac.

How do I get the same for Codex?

Codex has its own notification settings and hooks; see Codex notifications.

Why did my notification arrive a minute late?

That’s the idle_prompt timing: about 60 seconds after Claude finishes, and only if you haven’t typed. Use a Stop hook for an alert as soon as it finishes.

Sources: the Claude Code documentation on hooks, the hooks guide, terminal configuration, settings, Remote Control and the desktop app, read on October 26, 2026. Claude Code changes quickly; if something here no longer matches, write to meow@meowdoro.com.