Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code macOS Notifications

Get native macOS notifications from Claude Code so you know when it needs your attention — without staring at the terminal.

The problem

Token anxiety is real. You've got Claude working on something important, you switch tabs for 30 seconds, and now you have no idea if it finished, crashed, or is waiting on you.

When running Claude Code, you context-switch to other work while Claude is thinking. There's no way to know when Claude needs your attention without constantly checking back.

macOS Terminal.app doesn't support Claude Code's built-in notification escape sequences (only Kitty, Ghostty, and iTerm2 do). This repo is the fix.

How it works

Two independent notification hooks cover different scenarios:

1. Notification Hook — "Claude needs your input"

Fires when Claude Code sends a notification event: permission prompts, idle waiting, auth dialogs. Shows the working directory as the subtitle so you know which session it's from.

2. Stop Hook with Timer — "Claude finished a long task" (optional)

Fires when Claude finishes a response — but only if it took 15+ seconds. Quick replies are silent. Long tasks (code generation, debugging, multi-step work) get a notification.

Quick install

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Aman-Kothari7/claude-code-macos-notifications/main/install.sh)"

Or clone and run locally:

git clone https://github.com/Aman-Kothari7/claude-code-macos-notifications
cd claude-code-macos-notifications
./install.sh

Manual install

1. Install terminal-notifier

brew install terminal-notifier

2. Copy the hook scripts

mkdir -p ~/.claude/hooks
cp hooks/stamp-prompt.sh ~/.claude/hooks/
cp hooks/notify-on-stop.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/stamp-prompt.sh ~/.claude/hooks/notify-on-stop.sh

3. Add to ~/.claude/settings.json

For the Notification hook only (recommended starting point):

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.cwd // \"unknown\")\"' | xargs -I{} /opt/homebrew/bin/terminal-notifier -title 'Claude Code' -subtitle '{}' -message 'Waiting for your input' -sound Glass"
          }
        ]
      }
    ]
  }
}

To also enable the Stop hook (notify after 15+ second tasks):

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.cwd // \"unknown\")\"' | xargs -I{} /opt/homebrew/bin/terminal-notifier -title 'Claude Code' -subtitle '{}' -message 'Waiting for your input' -sound Glass"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/stamp-prompt.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/notify-on-stop.sh"
          }
        ]
      }
    ]
  }
}

4. Allow notifications

After the first notification fires, go to System Settings > Notifications > terminal-notifier and set:

  • Alert style: Banners or Alerts
  • Play sound for notifications: On
  • Allow notifications: On

Customisation

Change the notification sound: Replace Glass with any macOS system sound name (e.g. Ping, Funk, Blow, Pop). See /System/Library/Sounds/ for options.

Change the Stop hook threshold: Edit ~/.claude/hooks/notify-on-stop.sh and change the 15 in -ge 15 to your preferred number of seconds.

Change notification messages: Edit the -message values in settings.json.

Design decisions

Why terminal-notifier over osascript? osascript -e 'display notification ...' requires the calling app (Terminal.app) to have notification permissions. Terminal.app doesn't register in macOS notification settings until it successfully sends one — a chicken-and-egg problem. terminal-notifier is its own app and registers immediately.

Why absolute paths in settings.json? Hooks run in a minimal shell that may not load your full shell profile. /opt/homebrew/bin/terminal-notifier works reliably; bare terminal-notifier may not be found in PATH.

Why per-session stamp files? Multiple Claude Code sessions run concurrently. Using the session ID in the temp file path (/tmp/claude-prompt-stamp-${SESSION_ID}) prevents sessions from overwriting each other's timestamps.

Why 15 seconds for the Stop threshold?

  • < 15s: quick answers, confirmations, short responses — you're likely still at the terminal
  • ≥ 15s: multi-step work, code generation, debugging — you've probably switched away

Requirements

Contributing

Issues and PRs welcome. Common areas for improvement:

  • Support for non-Homebrew terminal-notifier paths (Intel Macs use /usr/local/bin/)
  • Linux support via notify-send
  • Different notification styles or sounds per hook type

License

MIT

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages