claude-plugins · notify

System notifications when Claude finishes.

macOS and Linux system notifications for Claude Code — duration-filtered so short tasks don't spam you. When Claude finishes a long job in the background, a notification fires carrying the repo name, branch, and Claude's actual last message.

notifications macos linux hooks
install + setupbash
claude plugin install notify@apurvbazari-plugins
/notify:setup
4
skills
3
events
2
platforms · macOS + Linux
1
config file
01 — how a notification fires

From Claude stopping to a system alert

A linear pipeline runs on every hook event. Click a stage to see detail in the side panel.

trigger
Claude stops
hook
notify.sh
filter
duration check
output
system notification

The duration filter is the key primitive — each event carries its own minDurationSeconds threshold. Below it, the script exits silently. Above it, it builds a repo / branch subtitle from git and extracts Claude's actual last message as notification content. The script always exits 0, so a missing backend or failed notification can never block Claude.

Intentionally minimal

notify does one thing well: native desktop alerts, duration-filtered, with project context. Install globally to get alerts across every Claude Code session, or per-project to tune settings per repo. Both scopes coexist — project-local inherits and overrides.

02 — 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. Edit notify-config.json directly — changes take effect immediately, no re-running setup.

EventWhenDefault soundminDurationSecondsDefault state
stop Claude finishes a response Hero 30 enabled
notification Claude needs your attention Glass 0 enabled
subagentStop A subagent finishes work disabled (too noisy)

stop fires on every Claude response — the 30-second default keeps it quiet for fast turns (typo fix, quick answer) while still firing on substantive work. notification always fires (threshold 0) because it means Claude is actively waiting on you. subagentStop is opt-in only.

03 — skills

Three user-facing skills

All under /notify:<name>. check is auto-invocable and read-only; setup and uninstall are destructive and require explicit user invocation.

SkillInvocationWhat it does
/notify:setup user-only Detects platform, installs the backend (terminal-notifier via Homebrew on macOS, notify-send from libnotify on Linux), detects your editor for click-to-focus, asks global vs per-project, configures all three events, and sends a test notification.
/notify:check auto Health check — reports which scopes are installed, shows the precedence-merged config the hook will actually use, and fires a test notification to confirm end-to-end wiring.
/notify:uninstall user-only Surgically 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.
wizard internal The interactive Q&A that customizes sounds, durations, matcher regex, and per-event toggles. A building block invoked by setup (user-invocable: false) — not a command you run.
04 — configuration

Per-event knobs in notify-config.json

All configuration lives in notify-config.json, written by /notify:setup. A project-local file inherits all global keys and overrides only what it sets — both scopes coexist. Edit directly after setup; the hook reads it on every invocation.

enabled
Event toggle

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

sound
Alert sound

14 macOS system sounds (Hero, Glass, Ping, Purr, Pop, Submarine, …). Maps to urgency level on Linux.

minDurationSeconds
Duration filter

Suppress this event if elapsed time is below this value. The substantive-work knob. Set 0 for always-fire.

activate
Click-to-focus

Bundle ID of the app to bring forward on notification click (e.g. VS Code, Cursor, iTerm2). macOS only.

message
Fallback text

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

scope precedence
Global + per-project

Install globally for all sessions, per-project to override. Project-local inherits all global keys and overrides what it sets.

05 — platform support

Cross-platform: macOS and Linux

Same hook, two backends. Duration filter and repo / branch subtitle work everywhere. Sounds and click-to-focus are richer on macOS.

macOS
terminal-notifier

14 system sounds, click-to-focus via bundle ID, title + subtitle + message, Homebrew install. JSON parsed via jq with python3 fallback.

Linux
notify-send / libnotify

Urgency levels (low/normal/critical mapped from sound setting), app-name, message body. Duration filter and repo/branch subtitle work identically.

WSL
Linux backend, caveats

notify-send reaches the Linux desktop only if a notification daemon is running. For Windows-side toasts, route through a Windows notifier (e.g. wsl-notify-send) or run Claude Code natively on Windows.

notify · v2.0.2 · MIT · by Apurv Bazari