OS Notifications for Claude Code on macOS

Coding with AI is basically the standard nowadays for many people. I also used it quite regularly in my job, specifically Claude Code. It’s certainly very useful to take care of boilerplate and repetitive code and other tasks; tell the AI to do the task, that would otherwise take you longer and be boring and let it work in the background (with proper security restraints of course), while I am getting a snack or so.
There is just one problem with that: It’s easy to forget time with your snack and forget to check when Claude is done or needs input from your side, resulting in it twiddling its imaginary thumbs not doing anything. And just like any good manager, I would never allow my employees a single free minute of not being productive.
Luckily there is a way to avoid that: Terminal Notifications!

Claude Code supports hooks — shell commands that run automatically at specific points in its lifecycle. With two small config entries and one Homebrew package, you can get native macOS notifications whenever Claude finishes a task or needs your input.

The Setup

Prerequisites

Install terminal-notifier, a CLI that posts to macOS Notification Center:

brew install terminal-notifier  

Configuration

Add two hooks to ~/.claude/settings.json:

{  
  "hooks": {  
    "Notification": [  
      {  
        "matcher": "*",  
        "hooks": [  
          {  
            "type": "command",  
            "command": "jq -r '.message' | xargs -I {} terminal-notifier -message \"{}\" -title \"Claude Code Alert\" -group \"$(pwd):notification\""  
          }  
        ]  
      }  
    ],  
    "Stop": [  
      {  
        "matcher": "*",  
        "hooks": [  
          {  
            "type": "command",  
            "command": "terminal-notifier -message \"Claude has completed its task in $(basename $(pwd))\" -title \"Claude Code Finished\" -group \"$(pwd):completion\""  
          }  
        ]  
      }  
    ]  
  }  
}  

That’s it. ~10 lines of JSON, no scripts, no daemons. And you get simple notifications whenever Claude is done with its current task:

OS-Notifications-for-Claude-Code-on-macOS-1771848834188.webp

There are more details and options to configure these notifications.

How It Works

Hook 1: Notification — “Claude Needs you”

Fires whenever Claude Code emits a notification — permission prompts, idle prompts, auth events, or questions. Claude pipes JSON to stdin:

{  
  "message": "Claude needs your permission to use Bash",  
  "title": "Permission needed",  
  "notification_type": "permission_prompt"  
}  

The command extracts the message field with jq and passes it to terminal-notifier. You see the actual notification text from Claude as a native macOS notification.

Notification types the matcher "*" catches:

TypeWhen it fires
permission_promptClaude needs you to approve a tool use
idle_promptClaude has been idle waiting for you
auth_successAuthentication completed
elicitation_dialogClaude is asking you a question

Hook 2: Stop — “Claude is done”

Fires whenever Claude finishes its response. The command sends a static notification with the current directory name for context, so you know which project Claude just finished working in.

Smart Notification Grouping

Both hooks use terminal-notifier’s -group flag:

  • Notification-group "$(pwd):notification"
  • Stop-group "$(pwd):completion"

This does two things:

  1. Per-workspace deduplication — new notifications from the same workspace replace old ones instead of stacking up
  2. Separate groups — “needs input” and “done” notifications don’t clobber each other because they use different group suffixes (:notification vs :completion)

JSON Payloads

Every hook receives common fields via stdin:

{  
  "session_id": "abc123",  
  "transcript_path": "/path/to/transcript.jsonl",  
  "cwd": "/current/working/directory",  
  "permission_mode": "default",  
  "hook_event_name": "Stop"  
}  

The Notification event adds message, title, and notification_type. The Stop event adds stop_hook_active (boolean) and last_assistant_message (Claude’s final response text).

All Available Hook Events

Claude Code supports 15 lifecycle hook events — Notification and Stop are just two of them:

EventWhen it fires
SessionStartSession begins or resumes
UserPromptSubmitUser submits a prompt, before processing
PreToolUseBefore a tool call executes (can block it)
PermissionRequestWhen a permission dialog appears
PostToolUseAfter a tool call succeeds
PostToolUseFailureAfter a tool call fails
NotificationWhen Claude sends a notification
SubagentStartWhen a subagent is spawned
SubagentStopWhen a subagent finishes
StopWhen Claude finishes responding
TeammateIdleWhen an agent team teammate is about to go idle
TaskCompletedWhen a task is marked completed
ConfigChangeWhen a config file changes during a session
PreCompactBefore context compaction
SessionEndWhen a session terminates

Further Reading