Desktop notifications for AI coding agents — get notified when Claude Code, OpenCode, or Pi finishes a task or needs your attention.
agent-notify is macOS-first, with basic notification support on Linux and Windows plus downloadable standalone binaries for those platforms.
AI agents can take minutes on complex tasks. Instead of watching the terminal, you get a desktop notification the moment your attention is needed — with a distinct sound per event type and smart suppression when you're already at the keyboard. On macOS, this uses a bundled native helper for the best experience.
- Native macOS notifications via a bundled helper app
- Basic Linux support via
notify-send - Basic Windows support via PowerShell / BurntToast fallback
- Three event types: done, question, and permission
- Compact context rows in the notification body for the current tab/project and Git branch
- Configurable sound per event (with live preview in the setup wizard)
- Bundled Agent Notify app icon on macOS
- Quiet hours
- Cooldown to avoid notification spam
- Focus detection — skips notification if your terminal is already in focus
- Optional macOS click-to-restore for the terminal app and Zellij tab
- Works with Claude Code and OpenCode out of the box
- Supports Pi via a tiny auto-discovered extension
- macOS — full feature set: native helper, app icon, sounds, optional click-to-restore, Homebrew install, and standalone tarballs
- Linux — basic notifications via
notify-send, with standalone release tarballs forx64andarm64 - Windows — basic notifications via PowerShell / BurntToast, with a standalone
x64release zip
brew tap piqusy/tap
brew install agent-notifyFor exact historical versions, use the standalone assets attached to each GitHub Release.
Download the asset matching your OS/CPU from the latest GitHub Release:
- macOS:
agent-notify-darwin-arm64.tar.gz,agent-notify-darwin-x64.tar.gz - Linux:
agent-notify-linux-arm64.tar.gz,agent-notify-linux-x64.tar.gz - Windows:
agent-notify-windows-x64.zip
Each archive contains the CLI binary under bin/ plus the bundled integration files.
- Download
agent-notify-windows-x64.zip - Extract it somewhere like
C:\Tools\agent-notify\ - Run the binary directly:
C:\Tools\agent-notify\bin\agent-notify.exe --versionOptional: add C:\Tools\agent-notify\bin to your PATH so you can run agent-notify from any terminal.
Requires 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 installs integrations for detected tools.
Manual integration wiring is also available:
agent-notify install all
agent-notify install claude-code
agent-notify install opencode
agent-notify install piRun the interactive wizard:
agent-notify initThis walks you through backend selection, terminal app focus detection, quiet hours, sound selection (with live preview), event selection, and optional macOS click-to-restore.
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 permission # send a "permission request" notification
agent-notify test done # send a test notification
agent-notify test permission # send a permission test notification
agent-notify sounds # list available sounds
agent-notify sounds --play Morse
agent-notify status # explain whether notifications would send right now
agent-notify explain # alias for status
agent-notify init # re-run setup wizard
agent-notify install all # install all supported integrations
agent-notify uninstall pi # remove one integrationNotifications use the title for the agent + event, and the body for compact context:
Pi — Done
▣ editor
⎇ main
▣shows the current Zellij tab name when available; otherwise it falls back to the project directory name⎇shows the current Git branch, or—when no branch is available
Install with:
agent-notify install claude-codeHooks are configured in ~/.claude/settings.json, and the hook scripts are copied into ~/.claude/hooks/agent-notify/:
| Hook | Event |
|---|---|
UserPromptSubmit |
Agent started working — marks the current Zellij pane/tab as working |
Stop |
Agent finished — sends done notification |
Notification |
Agent waiting for input — sends question notification |
PermissionRequest |
Agent needs permission — sends permission notification |
The working-state hook is a best-effort no-op outside Zellij. It only drives the live tab/pane indicator and does not show a desktop notification by itself.
Install with:
agent-notify install opencodeThis copies the plugin into ~/.config/opencode/plugins/opencode-agent-notify/ and updates ~/.config/opencode/opencode.json. It listens to chat.message, session.idle, session.error, and permission.asked hooks/events.
It emits:
- working indicator updates on
chat.message(best-effort prompt-submit timing; Zellij only, no desktop notification) - done for
session.idleandsession.error - permission for
permission.asked
Install with:
agent-notify install piThis copies agent-notify.ts into ~/.pi/agent/extensions/, which Pi auto-discovers on startup.
It emits:
- done when Pi finishes a turn
- question when the last assistant line ends with
? - nothing for aborted/error turns or assistant turns with no visible text, avoiding false-positive completion notifications
Pi does not have a built-in permission-request event, so there is no Pi permission notification.
Remove it later with:
agent-notify uninstall pi~/.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,
"clickRestore": {
"enabled": false
}
}terminalApp: null — auto-detected from terminal-specific env markers, $TERM_PROGRAM, and on macOS a parent-process fallback. This now covers common setups for iTerm2, Terminal, Warp, kitty, WezTerm, Hyper, Ghostty, Alacritty, VS Code, GNOME Terminal, Konsole, foot, Rio, and Tabby. Set it explicitly to e.g. "iTerm2" to override.
backend: null — auto-detected. On modern macOS this prefers the bundled native helper app, then falls back to osascript only if the helper is unavailable.
clickRestore.enabled: true — on macOS helper notifications, clicking the notification restores the terminal app, attempts to switch to the originating Zellij tab, and for kitty will also try to focus the originating kitty window when remote-control metadata is available.
sounds.permission: null — falls back to the question sound.
quietHours: null — disables quiet hours entirely (sounds play at all times).
Missing config fields are merged with defaults automatically. If the config contains invalid JSON or invalid values, agent-notify doctor reports the exact problems and invalid settings fall back to defaults until you save a corrected config.
- bun (for source install only — Homebrew install is standalone)
- macOS (source install): Xcode Command Line Tools / Swift so the native helper app can be built
- Linux:
notify-sendavailable onPATH - Windows: PowerShell available; BurntToast recommended for native toast notifications
Run the built-in diagnostic tool:
agent-notify doctorIt checks config validity, backend detection, notification permissions, focus state, quiet hours, helper availability, and sound files in one pass.
For a faster "would this notify right now?" view, run:
agent-notify status
agent-notify status --tool claude-code
agent-notify explain --tool opencodeThis reports the effective backend, detected terminal app, how it was detected, current focus state, quiet-hours state, cooldown state, and whether done, question, and permission would currently send or be suppressed.
For popup-vs-tab-indicator race debugging, capture core timing and macOS helper timing side by side:
export AGENT_NOTIFY_DEBUG_LOG=/tmp/agent-notify-debug.jsonl
export AGENT_NOTIFY_MACOS_HELPER_LOG=/tmp/agent-notify-helper.logThen reproduce one notification and inspect:
AGENT_NOTIFY_DEBUG_LOG— JSONL from core flow, includingtab-indicator-start,tab-indicator-end,git-branch-start,git-branch-end,notification-send-start,notification-send-end, and macOS launch events likemacos-helper-launch-startAGENT_NOTIFY_MACOS_HELPER_LOG— native helper log lines after helper process starts
This makes it easy to see whether lag comes from Zellij rename timing, Git branch lookup, helper launch, or Notification Center display timing.
If ~/.config/agent-notify/config.json contains invalid JSON or bad values, agent-notify no longer silently resets everything. Invalid settings are reported by agent-notify doctor, and only those broken settings fall back to defaults until you fix and save the file again.
bun install
bun run sync:version
bun run build
bun run testpackage.json at the workspace root is now the canonical version source. Run bun run sync:version after changing it to update the workspace package versions and generated CLI version constant.
For Claude Code specifically, rerun agent-notify install claude-code after editing files under packages/claude-code/hooks/, then start a fresh Claude Code session so the updated hooks and settings are picked up.
For OpenCode specifically, rerun ./install.sh after building so ~/.config/opencode/opencode.json points at local plugin path, then start fresh OpenCode session and trigger session.idle or permission.asked.
For Pi specifically, rerun ./install.sh after editing packages/pi-coding-agent/src/agent-notify.ts so the latest extension is copied into ~/.pi/agent/extensions/agent-notify.ts.
- macOS notification permissions — the most common issue. Open System Settings → Notifications → Agent Notify and enable Allow Notifications. Set the alert style to Banners or Alerts.
- macOS native helper missing — if you installed from source on macOS, rerun
bun run buildand make sure the helper app was built successfully. - Linux backend — make sure
notify-sendis installed and available onPATH, even when using the standalone binary. - Windows backend — make sure PowerShell is available. BurntToast is preferred; without it, agent-notify falls back to a message box.
- Windows standalone zip — after extracting, run
bin\\agent-notify.exe --versiononce to confirm the binary starts before wiring integrations. - Fallback backend — if the macOS helper app is unavailable, agent-notify can fall back to
osascript, but the bundled helper is the supported macOS path. - Focus detection — if your terminal is the frontmost app, notifications are suppressed by design.
agent-notify statusandagent-notify doctornow show which terminal was detected and why. If auto-detection is wrong on your machine, set"terminalApp"explicitly in config.
For native Windows toast notifications, install the BurntToast PowerShell module:
Install-Module BurntToast -Scope CurrentUserIf PowerShell asks to trust PSGallery, accept it. After installing, restart your terminal/PowerShell session and rerun agent-notify test done --force.
Without BurntToast, agent-notify falls back to a simple message box. That fallback still notifies you, but it is less native than a proper toast.
- Check that Sounds is toggled on in System Settings → Notifications → Agent Notify.
- 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).
- Linux and Windows backends are more limited than macOS; sound behavior is currently macOS-first.
On modern macOS, agent-notify uses its bundled native helper app by default. This is the supported path for reliable notifications, the branded Agent Notify app icon, and click-to-restore when enabled. For kitty, exact window/tab restore is best-effort and depends on kitty remote control being addressable (for example via KITTY_LISTEN_ON / listen_on).
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