Desktop notifications for AI coding agents — get notified when Claude Code or OpenCode finishes a task, asks a question, or needs your permission.
AI agents can take minutes on complex tasks. Instead of watching the terminal, you get a native macOS notification the moment your attention is needed — with a distinct sound per event type and smart suppression when you're already at the keyboard.
- Native macOS notifications (terminal-notifier or osascript)
- Three event types: done, question, permission request
- Configurable sound per event (with live preview in the setup wizard)
- Quiet hours
- Cooldown to avoid notification spam
- Focus detection — skips notification if your terminal is already in focus
- Works with Claude Code and OpenCode out of the box
brew tap piqusy/tap
brew install agent-notifyRequires bun.
git clone https://github.com/piqusy/agent-notify.git
cd agent-notify
./install.shinstall.sh builds the project, links the CLI, runs the setup wizard, and wires Claude Code hooks and the OpenCode plugin automatically — with graceful fallbacks if either tool isn't installed.
Run the interactive wizard:
agent-notify initThis walks you through backend selection, terminal app focus detection, quiet hours, sound selection (with live preview), and which events to enable.
Config is saved to ~/.config/agent-notify/config.json.
agent-notify done # send a "done" notification
agent-notify question # send a "question" notification
agent-notify test done # send a test notification
agent-notify sounds # list available sounds
agent-notify sounds --play Morse
agent-notify init # re-run setup wizardHooks are configured in ~/.claude/settings.json. After running ./install.sh or wiring manually:
| Hook | Event |
|---|---|
Stop |
Agent finished — sends done notification |
Notification |
Agent waiting for input — sends question notification |
PermissionRequest |
Agent needs permission — sends question notification |
The opencode-agent-notify plugin is added to ~/.config/opencode/opencode.json automatically by install.sh. It listens to session.idle and permission.updated events.
~/.config/agent-notify/config.json:
{
"cooldownSeconds": 3,
"quietHours": { "start": 22, "end": 8 },
"sounds": {
"done": "Morse",
"question": "Submarine",
"permission": null
},
"events": {
"done": true,
"question": true,
"permission": true
},
"terminalApp": null,
"backend": null
}terminalApp: null — auto-detected via $TERM_PROGRAM. Set to e.g. "iTerm2" to override.
backend: null — auto-detected (prefers terminal-notifier if installed, falls back to osascript).
sounds.permission: null — falls back to the question sound.
quietHours: null — disables quiet hours entirely (sounds play at all times).
- macOS
- bun (for source install only — Homebrew install is standalone)
- terminal-notifier (optional, for richer notifications —
brew install terminal-notifier)
Run the built-in diagnostic tool:
agent-notify doctorIt checks config validity, backend detection, notification permissions, focus state, quiet hours, and sound files in one pass.
- macOS notification permissions — the most common issue. Open System Settings → Notifications → terminal-notifier and enable Allow Notifications. Set the alert style to Banners or Alerts.
- Backend not installed — if using
terminal-notifier(recommended), install it:brew install terminal-notifier. - Focus detection — if your terminal is the frontmost app, notifications are suppressed by design. Switch to another app or set
"terminalApp": nullin config to disable focus detection entirely.
- Check that Sounds is toggled on in System Settings → Notifications → terminal-notifier.
- Check that your system volume is not muted.
- Verify your sound config refers to a valid built-in name:
agent-notify sounds. - During quiet hours, sounds are muted (notifications still appear silently).
Sequoia restricts some notification APIs. Use terminal-notifier as the backend — osascript notifications may not work. Install it with brew install terminal-notifier.
The test command now reports whether the notification was actually sent or suppressed (and why). If you see Notification suppressed (reason), the notification was intentionally skipped — run agent-notify doctor to understand why.
MIT © Ivan Ramljak