An open API service indexing awesome lists of open source software.

https://github.com/DevinoSolutions/ai-agent-notifier

Desktop & phone notifications for AI coding agents (Claude Code, Codex, Gemini CLI, Cursor). Native VS Code support. Toast + ntfy push. Zero dependencies.
https://github.com/DevinoSolutions/ai-agent-notifier

ai-agent ai-coding claude-code cli codex coding-agent cross-platform cursor desktop-notifications developer-tools gemini-cli hooks nodejs notifications ntfy productivity push-notifications toast vscode

Last synced: 8 days ago
JSON representation

Desktop & phone notifications for AI coding agents (Claude Code, Codex, Gemini CLI, Cursor). Native VS Code support. Toast + ntfy push. Zero dependencies.

Awesome Lists containing this project

README

          

ai-agent-notifier


Desktop & phone notifications for AI coding agents

One tool. One config. Every agent. Never miss when your AI finishes or needs input.


Claude Code  
Codex CLI  
Cursor  
Gemini CLI  
VS Code


npm version
npm downloads
License: AGPL-3.0
Node.js >= 18
Zero Dependencies


Windows
macOS
Linux
Android
iOS

---

## Demo

https://github.com/user-attachments/assets/5714b528-7e04-478e-abfd-2a3d05db562c

[Watch with sound on YouTube](https://www.youtube.com/watch?v=QVVOIIud4-I)

## Quick Start

```bash
npx ai-agent-notifier setup
```

That's it. The setup wizard detects your platform and installed AI tools, wires the hooks, and optionally configures phone push notifications. Restart your AI tools to activate.

## Features

- **Desktop toast notifications** -- Windows (BurntToast), macOS (Notification Center), Linux (libnotify)
- **WSL-native toasts** -- real Windows toast notifications from inside WSL, no Linux notification daemon needed
- **Phone push notifications** -- Android & iOS via [ntfy](https://ntfy.sh) (free, no account required)
- **Webhook notifications** -- Slack, Discord, Telegram, or any HTTP endpoint, with an optional auth header
- **Rich notification content** -- Claude Code toasts and webhooks show what the agent actually said or asked, not a generic line
- **Terminal bell** -- audible ding in the terminal that launched the agent (works over SSH/tmux)
- **Click-to-focus** -- click the toast to jump back to the terminal or VS Code window (Windows)
- **Codex approval alerts** -- get notified the instant Codex asks for permission, not just when it finishes
- **Per-tool branded icons** -- each tool gets its own logo in the notification
- **One unified config** -- shared `~/.ai-agent-notifier/config.json` across all tools
- **Atomic deduplication** -- prevents double notifications (e.g. Cursor's duplicate hook fires)
- **Zero dependencies** -- pure Node.js built-ins only, no npm production packages

## Supported Tools


Tool
VS Code
CLI
Task Complete
Needs Input


  Claude Code
Native
Native
Stop
Notification


  Codex CLI
Native
Native
Stop
PermissionRequest


  Cursor
Native
--
stop
--


  Gemini CLI
--
Native
AfterAgent
Notification

All four tools are wired automatically by the setup wizard. No manual config editing needed. Codex's `PermissionRequest` hook fires the same "needs your input" alert when Codex asks for approval to run a command -- verified with Codex CLI >=0.144.0.

### VS Code Native Support

Claude Code, Codex, and Cursor all run inside VS Code. **ai-agent-notifier** hooks directly into each tool's native hook system -- no VS Code extension required. The setup wizard detects installed tools and patches their configs automatically. Click a notification toast to jump straight back to your VS Code window.

## Installation

### npm (recommended)

```bash
# One-shot setup (no install needed)
npx ai-agent-notifier setup

# Or install globally
npm i -g ai-agent-notifier
ai-agent-notifier setup
```

### Claude Code Plugin

```
/install-plugin https://github.com/DevinoSolutions/ai-agent-notifier
```

Hooks auto-register. Use `/ai-agent-notifier:setup` to wire other tools.

### Standalone (no npm)

**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/DevinoSolutions/ai-agent-notifier/main/setup/install.ps1 | iex
```

**macOS / Linux:**
```bash
curl -fsSL https://raw.githubusercontent.com/DevinoSolutions/ai-agent-notifier/main/setup/install.sh | bash
```

## CLI Commands

```
ai-agent-notifier setup # First-time setup wizard
ai-agent-notifier status # Show wired tools, config, backends
ai-agent-notifier test [channel] # Fire test notification (toast | ntfy | webhook | bell | both)
ai-agent-notifier config # Interactive settings menu
ai-agent-notifier uninstall # Remove hooks from all tools
```

## Configuration

Config lives at `~/.ai-agent-notifier/config.json`:

```json
{
"ntfy": {
"enabled": true,
"server": "https://ntfy.sh",
"topic": "ai-agent-notifier-",
"click": ""
},
"toast": {
"enabled": true,
"clickToFocus": true
},
"terminalBell": {
"enabled": true
},
"webhook": {
"enabled": false,
"url": "",
"format": "generic"
},
"sentry": {
"enabled": false,
"dsn": ""
},
"events": {
"task_complete": { "toastSound": "IM", "priority": "default" },
"needs_input": { "toastSound": "Reminder", "priority": "urgent" },
"session_start": { "toastSound": "Default", "priority": "low", "terminalBellEnabled": false }
}
}
```

`ntfy.click` is the URL opened when you tap a phone notification (empty = no link). `terminalBell` rings the terminal that launched the agent -- for Claude Code (>=2.1.141) it rings through Claude Code's own terminal write path (hook JSON `terminalSequence`), which is safe in tmux, GNU screen, and on Windows per Claude Code's docs; other agents get a direct TTY/console bell. `webhook` posts to Slack, Discord, Telegram, or any URL (see below). `sentry` is opt-in error reporting (see [Error visibility](#error-visibility)). Per-event `toastSound` names a Windows [BurntToast](https://github.com/Windos/BurntToast) sound and is ignored on macOS/Linux; `priority` (`min` / `low` / `default` / `high` / `urgent`) drives both the ntfy push priority and the Linux `notify-send` urgency.

### ntfy -- Phone Push Notifications

[ntfy](https://ntfy.sh) sends free push notifications to your phone -- no account needed.

1. Install the ntfy app ([Android](https://play.google.com/store/apps/details?id=io.heckel.ntfy) / [iOS](https://apps.apple.com/app/ntfy/id1625396347))
2. Subscribe to your topic (shown during setup)
3. All your AI tools' notifications appear in one stream

### Webhook -- Slack, Discord, Telegram, or anything

Set `webhook.enabled: true` and a `webhook.url` to POST a notification to any HTTP endpoint. `format` selects the payload shape:

**Slack:**
```json
{
"webhook": {
"enabled": true,
"url": "https://hooks.slack.com/services/...",
"format": "slack"
}
}
```

**Discord:**
```json
{
"webhook": {
"enabled": true,
"url": "https://discord.com/api/webhooks/...",
"format": "discord"
}
}
```

**Telegram:**
```json
{
"webhook": {
"enabled": true,
"url": "https://api.telegram.org/bot/sendMessage",
"format": "telegram",
"chatId": "123456789"
}
}
```

**Generic (anything else):**
```json
{
"webhook": {
"enabled": true,
"url": "https://example.com/hook",
"format": "generic",
"authorization": "Bearer "
}
}
```
Generic POSTs `{title, message, source, project, event, timestamp}` as JSON. `authorization`, if set, is sent as the `Authorization` header for any format, not just generic.

Webhook failures are logged with the URL's origin only, never the full URL -- a Slack/Discord webhook URL or a Telegram bot token is a secret, and errors.log can be mirrored to Sentry.

Test it with `ai-agent-notifier test webhook`, or turn it off for one event type with `"events": {"task_complete": {"webhookEnabled": false}}`.

### Rich notification content

For Claude Code, toast and webhook notifications show what actually happened instead of a generic "task complete" line: a "needs input" notification carries Claude's own question, and a "task complete" notification carries the last assistant message, both read from the Claude Code transcript and trimmed to a short snippet. Session-start notifications stay generic (nothing to show yet). Other agents (Codex, Cursor, Gemini) always get the generic text -- transcript reading is Claude Code-only.

Controlled per channel:

| Channel | Config key | Default |
|---------|-----------|:-------:|
| Toast | `toast.richContent` | `true` |
| Webhook | `webhook.richContent` | `true` |
| ntfy | `ntfy.richContent` | `false` |

`ntfy.richContent` defaults to **false** for privacy: the default `ntfy.sh` server is public, ntfy topic names are guessable rather than access-controlled secrets, and a snippet of your conversation would leak to anyone who guesses or stumbles on your topic. Only enable `ntfy.richContent` if you run your own private ntfy server, or you've deliberately accepted that risk on the public one.

### Per-Event Settings

| Event | Default `toastSound` | Default `priority` | Description |
|-------|:------------:|:-------------:|-------------|
| `task_complete` | IM | default | Agent finished its task |
| `needs_input` | Reminder | urgent | Agent needs your input or permission |
| `session_start` | Default | low | New session started (all channels off by default) |

### Error visibility

Hook and channel errors never interrupt your agent -- they're appended to `~/.ai-agent-notifier/errors.log` and surfaced by `npx ai-agent-notifier status`, so a misconfigured toast backend or unreachable ntfy topic shows up as a logged error instead of a silent no-op. Set `sentry.enabled` to `true` (with a `sentry.dsn`) to also mirror those errors to [Sentry](https://sentry.io) through a built-in, zero-dependency envelope client: no SDK is bundled, no telemetry is collected, and nothing leaves your machine unless you opt in -- only error data is sent.

## How It Works

Each AI tool's hook system pipes event data to `notify.mjs`:

```
Hook fires (stdin JSON + --source flag)
-> parse-input.mjs (normalize across tools)
-> router.mjs (map event to notification type)
-> transcript.mjs (Claude Code only: derive rich message text)
-> platform toast (Windows / macOS / Linux / WSL)
-> ntfy push (phone notification)
-> webhook POST (Slack / Discord / Telegram / generic)
-> terminal bell (Claude Code: terminalSequence in the hook reply;
other tools: BEL to the controlling terminal)
```

## Platform Details

### Windows

- [BurntToast](https://github.com/Windos/BurntToast) PowerShell module for rich toast notifications
- Click-to-focus via custom `agentfocus://` URI protocol
- BurntToast auto-installed during setup if missing
- Requires PowerShell 7+ (pwsh)

### macOS

- Uses built-in `osascript` -- zero additional dependencies
- Falls back to `terminal-notifier` for richer features if available

### Linux

- Uses `notify-send` (libnotify) -- available on most desktop distributions
- Fails silently on headless systems without a GUI (see WSL below for WSL2)

### WSL

- Auto-detected -- no config needed
- Toast notifications route to a real Windows toast via PowerShell interop (`powershell.exe`/`pwsh.exe` across the `/mnt/c` boundary), not `notify-send`/D-Bus
- Needs WSL2 interop enabled and a Windows PowerShell present -- both are on by default
- Terminal bell and ntfy behave exactly as on native Linux

## Requirements

| Requirement | Details |
|-------------|---------|
| **Node.js** | >= 18.0.0 (already present for all supported AI tools) |
| **Windows** | PowerShell 7+ (pwsh) |
| **macOS** | osascript (built-in) |
| **Linux** | notify-send (optional, for desktop toasts) |

## Uninstall

```bash
ai-agent-notifier uninstall
```

Removes all managed hooks from every tool's config. Original configs are backed up at `~/.ai-agent-notifier/backups/`.

## Testing

Everything below is verified against the **real thing** — no mocks, no stubs, no fakes. Real ntfy.sh push delivery, a real Linux notification daemon receiving the exact payload, the real agent CLIs installed from npm and driven end to end, and the real native OS toast backends actually firing. Every job is **required** and **hard-fails**: a broken key, a renamed secret, or a hook that doesn't deliver turns CI red instead of skipping silently.

### What CI verifies on every run — all real, all platforms

Each job runs as its own GitHub Actions workflow. The badge in every row is its **live status on `main`** — not a screenshot — so click any badge to see the actual run and its per-test logs.



Job
Live status
Platforms
What is actually exercised (no mocks)




Unit
Unit
Linux · macOS · Windows
The full unit + integration suite against the real exported code (not inline copies)


E2E real-world
E2E
Linux · macOS · Windows
Real setup/uninstall subprocesses against an isolated HOME · real notify.mjs hook invocation per source · real ntfy.sh round-trip (push sent, then read back off the server)


Install + smoke-load
Agents
Linux · macOS · Windows
Installs the real Claude, Codex, Gemini (and Cursor where available) CLIs from npm, asserts they launch, and smoke-loads each hook (Codex classification pinned — drift fails CI)


Live Claude
Live Claude
Linux
Drives the real Claude CLI end to end (paid); hard-fails if the hook doesn't deliver a notification


Live Gemini
Live Gemini
Linux
Drives the real Gemini CLI end to end; hard-fails if the hook doesn't deliver a notification


Live Codex
Live Codex
Linux
Validates OPENAI_API_KEY against the live OpenAI API + the real Codex config-patch wiring ¹


Live Cursor
Live Cursor
Linux
Validates the real Cursor config-patch wiring (BYO key) ¹


Live Toast Linux
Toast Linux
Linux
Fires through the real notify-send backend into a real dunst daemon, then reads its history and asserts it captured the exact title + body


Live Toast Native
Toast Native
macOS · Windows
Fires the real osascript / BurntToast backend and asserts the OS accepted the toast

¹ Codex and Cursor don't round-trip a prompt through their API in CI — `codex exec` needs OpenAI Tier 1+ WebSocket access, and Cursor is a GUI editor. Their hook **delivery** is fully covered by the unit + e2e suites; these jobs verify the live key and the real config wiring.

### Run it yourself

```bash
npm test # offline: the full unit + integration suite
npm run test:e2e # real ntfy.sh round-trip, needs network
npm run toast:demo # fire real desktop toasts, every event
```

### The one thing CI can't prove

Headless CI has no display or login session, so it verifies **delivery** (a real daemon received the payload) and **backend success** (the OS accepted the call) — but it cannot prove a human visually *sees* a banner appear. macOS and Windows also silently suppress toasts under Do Not Disturb / Focus or denied notification permission, returning success either way. To confirm with your own eyes on your own machine, run `npm run toast:demo` and watch them pop.

## Contributing

Contributions are welcome. Please open an issue first to discuss what you'd like to change.

## License

[AGPL-3.0](LICENSE) -- Copyright (c) 2026 [DevinoSolutions](https://github.com/DevinoSolutions)