claude-plugins · notify

Desktop notifications, only when it matters.

notify fires a macOS or Linux system notification when Claude Code finishes a task — carrying a repo / branch subtitle and Claude's actual last message. A per-event duration filter suppresses fast responses, so it only interrupts you when Claude has genuinely been working.

plugin notifications hooks macos · linux
installbash
claude plugin install notify@apurvbazari-plugins

Then run /notify:setup to install the platform backend and wire the hooks.

3
user skills
3
hook events
2
platforms
2
install scopes
0
CDN deps
01 — what it does

A Stop-hook wrapper around your system notifier

/notify:setup detects your platform, installs the backend if needed (terminal-notifier via Homebrew on macOS, or notify-send from libnotify on Linux), detects your editor for click-to-focus, asks whether to install globally or per-project, and wires the hooks.

When Claude stops, the hook runs notify.sh, which reads your per-event config, extracts Claude's actual last message (not generic static text), builds a contextual repo / branch subtitle from git, and posts the notification. The script always exits 0 — a missing backend or a failed notification never blocks Claude.

Intentionally minimal

notify does one thing well: native desktop alerts, duration-filtered, with project context. For richer feature sets, the root README compares it honestly against community alternatives.

02 — the duration filter

The duration filter

Each event carries a minDurationSeconds threshold. If the elapsed time since last activity is below it, the notification is silently skipped — so a 4-second typo fix never interrupts you, but a 12-minute refactor does.

track
elapsed vs threshold
under
silently skipped
over
delivered

The wrapper tracks last activity in a temp file ($TMPDIR/claude-notify-session-start). The filter applies to stop and subagentStop — set 30 on stop for substantive-work-only alerts. Leave 0 on notification so attention prompts always fire.

03 — how it fires

From Claude stopping to a system alert

A fixed pipeline runs on every hook event. Click a stage for detail.

trigger
Claude stops
hook
notify.sh
filter
duration check
build
message + subtitle
post
system alert

The backend is chosen by platform: terminal-notifier on macOS (title, subtitle, message, sound, click-to-activate), or notify-send on Linux (app-name, urgency, message). JSON from stdin is parsed with a jq-first / python3-fallback helper, so neither tool is a hard dependency.

04 — reference

Skills & the setup wizard

Three user-facing skills (all /notify:<name>). check is auto-invocable; the two destructive skills require explicit invocation. One internal wizard is hidden from the menu.

SkillInvocationWhat it does
/notify:setupuser-onlyDetects platform, installs the backend, detects your editor + bundle ID for click-to-focus, asks global vs per-project, wires the hooks, and sends a test notification.
/notify:checkautoHealth check — reports which scopes are installed, the event configuration, the precedence-merged config the hook will actually use, and sends a test notification to confirm the wiring end-to-end.
/notify:uninstalluser-onlySurgically removes notify-owned hooks from settings.json, deletes notify-config.json, and offers to uninstall the backend if nothing else depends on it. Leaves unrelated hooks untouched.
/notify:wizardinternalThe preference Q&A — sounds, durations, per-event toggles, matcher regex. Invoked by setup; hidden from the / menu.
05 — event model

Three events, each independently configurable

Notification content is extracted from Claude's real last message. Each event has its own enabled flag, sound, and duration threshold.

EventWhenDefault
stopClaude finishes a responseEnabled · Hero sound · minDurationSeconds: 30
notificationClaude needs your attentionEnabled · Glass sound · minDurationSeconds: 0
subagentStopA subagent finishes workDisabled (too noisy by default)
per-event knobs — edit notify-config.json, takes effect immediately
enabled
Toggle

Turn any event on or off without re-running setup.

sound
Alert sound

Hero, Glass, Ping, Purr, Pop, Submarine and more on macOS; urgency level on Linux.

minDurationSeconds
Duration filter

Suppress this event below the elapsed-time threshold. The substantive-work knob.

activate
Click-to-focus

App to bring forward on click (VS Code, Cursor, iTerm2, …) via bundle ID — macOS only.

message
Fallback text

Shown when contextual content can't be extracted from Claude's response.

scope precedence
Global + per-project

Project-local inherits all global keys and overrides only what it sets. Both scopes coexist.

06 — platform support

Cross-platform: macOS and Linux

Same hook, two backends. The duration filter and the repo / branch subtitle work everywhere; sounds and click-to-focus are richer on macOS.

CapabilitymacOSLinux
Backendterminal-notifiernotify-send (libnotify)
Sound14 system soundsUrgency levels only
Click-to-focus✓ via bundle ID— not supported
Duration filter
repo / branch subtitle
JSON parsingjq → python3 fallbackjq → python3 fallback
07 — example

One run, then the filter at work

/notify:setup on macOS, then a Stop hook firing in two scenarios — one suppressed by the duration filter, one delivered.

/notify:setup → Stop hook ×2transcript
> /notify:setup

Detecting platform … macOS
Checking for terminal-notifier … installing via Homebrew
Editor detected: VS Code (com.microsoft.VSCode)

Where should notifications be installed?
  (a) Global — fire in every Claude Code session
  (b) This project only

> a

Configuring three events:
  stop          enabled   sound: Hero    minDurationSeconds: 30
  notification  enabled   sound: Glass   minDurationSeconds: 0
  subagentStop  disabled  (too noisy by default)

Writing notify-config.json to ~/.claude/
Adding hooks to ~/.claude/settings.json (Stop, Notification)
Sending test notification … ✓

# ── short task: "fix typo in README" ────────
[Stop hook fires]
[notify.sh: elapsed 4s < 30s threshold → silently skip]
(no notification — duration filter suppressed)

# ── long task: 12-minute refactor ───────────
[Stop hook fires]
[notify.sh: elapsed 743s ≥ 30s → notify]

  ┌──────────────────────────────────────┐
  │ Claude Code                          │
  │ feedback-saas / feat/onboarding-flow │
  │ Refactored auth middleware …         │
  └──────────────────────────────────────┘

  Sound: Hero · Click brings VS Code to front
notify · v2.0.0 · MIT · by Apurv Bazari