Notification bot for Claude Code hook events. Get notifications via Desktop, Telegram, Slack, Discord, ntfy, Pushbullet, Teams, Webhook, Email, WhatsApp, or OpenClaw when Claude needs your input — permission prompts, questions, idle sessions, or task completions.
Built in Rust for a single native binary with no runtime dependencies.
When running Claude Code sessions (especially long-running or parallel ones), sessions sit idle waiting for attention. claude-notify sends notifications so you can monitor from mobile or another screen — and quickly switch between backends depending on where you are.
The easiest way to use claude-notify is as a Claude Code plugin. The plugin auto-registers all hooks and provides namespaced slash commands — no manual configuration needed.
# 1. Install the binary
curl -sSL https://raw.githubusercontent.com/hecspc/claude-notify/main/install.sh | sh
# 2. Install the plugin (auto-registers hooks)
claude plugin install claude-notify
# 3. Configure a backend via slash command
/claude-notify:setup-desktop
/claude-notify:setup-telegram <BOT_TOKEN> <CHAT_ID>| Skill | Description |
|---|---|
/claude-notify:setup-desktop |
Enable native OS notifications (zero-config) |
/claude-notify:setup-telegram |
Configure Telegram bot notifications |
/claude-notify:setup-slack |
Configure Slack webhook notifications |
/claude-notify:setup-discord |
Configure Discord webhook notifications |
/claude-notify:setup-ntfy |
Configure ntfy push notifications |
/claude-notify:setup-pushbullet |
Configure Pushbullet notifications |
/claude-notify:setup-teams |
Configure Microsoft Teams notifications |
/claude-notify:setup-webhook |
Configure generic webhook notifications |
/claude-notify:setup-email |
Configure email (SMTP) notifications |
/claude-notify:setup-whatsapp |
Configure WhatsApp notifications via Meta Cloud API |
/claude-notify:setup-openclaw |
Configure OpenClaw Gateway notifications |
/claude-notify:use |
Switch active backends (e.g. desktop,slack) |
/claude-notify:mute |
Mute notifications globally or for a session |
/claude-notify:unmute |
Unmute notifications |
/claude-notify:status |
Show current mute status |
/claude-notify:session |
Toggle mute for the current session |
If you prefer not to use the plugin, you can install the binary and use setup to configure hooks manually.
# Install latest version
curl -sSL https://raw.githubusercontent.com/hecspc/claude-notify/main/install.sh | sh
# Install a specific version
curl -sSL https://raw.githubusercontent.com/hecspc/claude-notify/main/install.sh | sh -s 1.0.1
# Custom install directory (default: ~/.local/bin)
curl -sSL https://raw.githubusercontent.com/hecspc/claude-notify/main/install.sh | INSTALL_DIR=/usr/local/bin shOr build from source:
cargo build --release
cp target/release/claude-notify ~/.local/bin/# One-command setup: configures credentials + hooks + Claude Code skills
claude-notify setup desktop # zero-config native OS notifications
claude-notify setup telegram YOUR_BOT_TOKEN YOUR_CHAT_ID # Telegram
claude-notify setup slack https://hooks.slack.com/services/T.../B.../xxx # Slack
claude-notify setup discord https://discord.com/api/webhooks/123/abc # Discord
claude-notify setup email me@x.com me@x.com smtp.x.com user pass # Email (SMTP)
claude-notify setup ntfy https://ntfy.sh/my-claude-topic # ntfy
claude-notify setup pushbullet YOUR_API_TOKEN # Pushbullet
claude-notify setup teams https://xxx.webhook.office.com/... # Microsoft Teams
claude-notify setup webhook https://example.com/notify # generic webhook
claude-notify setup webhook ha-appletv http://ha:8123/api/webhook/x # named webhook instance
claude-notify setup whatsapp PHONE_ID ACCESS_TOKEN 14155551234 # WhatsApp
claude-notify setup openclaw http://localhost:3000 TOKEN +1555551234 # OpenClaw
# Switch backends on the fly
claude-notify use desktop # at my desk
claude-notify use slack # going AFK
claude-notify use desktop,slack # bothThis writes ~/.config/claude-notify/config.toml with your credentials, adds hooks to ~/.claude/settings.json, and installs Claude Code slash commands (/notify-mute, /notify-unmute, /notify-use, /notify-session).
| Event | Icon | Description |
|---|---|---|
| Permission prompt | 🔔 | Claude needs tool approval (Bash, Edit, etc.) |
| Idle prompt | ⏳ | Claude is waiting for your response |
| Elicitation dialog | ❓ | Claude is asking a question |
| Response complete | ✅ | Claude finished responding (includes last message summary) |
| Task completed | 🎉 | A background task finished (includes task subject, teammate, description) |
🔔 Permission Required
Session: safe-seal (66a021e0) | engineering-bot
─────────────────
Tool: Bash
Action: npm install express
✅ Response Complete
Session: safe-seal (66a021e0) | engineering-bot
─────────────────
I've updated the README.md with the new setup instructions and rebuilt the release binary.
🎉 Task Completed
Session: pink-swan (abc123) | engineering-bot
Task: Implement notification system
Teammate: implementer
─────────────────
Add Telegram notifications for Claude Code hook events
Sessions are identified by a friendly name derived from the session_id (e.g. safe-seal) plus the short UUID and project name, for quick identification across parallel sessions.
claude-notify # Normal: read hook JSON from stdin, notify
claude-notify setup telegram <BOT_TOKEN> <CHAT_ID> # Configure credentials + hooks (user-level)
claude-notify setup telegram <BOT_TOKEN> <CHAT_ID> --project # Configure hooks in current project
claude-notify setup slack <WEBHOOK_URL> # Configure Slack notifications
claude-notify setup desktop # Configure desktop notifications (zero-config)
claude-notify setup email <FROM> <TO> <HOST> <USER> <PASS> # Configure email via SMTP
claude-notify setup discord <WEBHOOK_URL> # Configure Discord notifications
claude-notify setup ntfy <TOPIC_URL> # Configure ntfy notifications
claude-notify setup pushbullet <API_TOKEN> # Configure Pushbullet notifications
claude-notify setup teams <WEBHOOK_URL> # Configure Microsoft Teams notifications
claude-notify setup webhook <URL> # Configure generic webhook (unnamed)
claude-notify setup webhook <NAME> <URL> # Configure named webhook instance
claude-notify setup whatsapp <PHONE_ID> <TOKEN> <RECIPIENT> # Configure WhatsApp via Meta Cloud API
claude-notify setup openclaw <URL> <TOKEN> <TARGET> # Configure OpenClaw Gateway notifications
claude-notify use desktop # Switch active backend(s)
claude-notify use desktop,slack # Multiple backends
claude-notify mute # Mute all notifications
claude-notify mute safe-seal # Mute a specific session (friendly name or UUID)
claude-notify unmute # Unmute all
claude-notify unmute safe-seal # Unmute a specific session
claude-notify status # Show mute status
claude-notify --dry-run # Print formatted message to stdout, don't send
claude-notify --version # Print version
Setup installs these slash commands into Claude Code:
| Skill | Description |
|---|---|
/notify-mute |
Mute all notifications, or pass a session name to mute one |
/notify-unmute |
Unmute all notifications, or pass a session name to unmute one |
/notify-use |
Switch active backends (e.g. /notify-use desktop,slack) |
/notify-session |
Toggle mute for the current session (no args needed) |
Mute notifications globally or per-session. Use the friendly name from the notification (e.g. safe-seal) or the raw session UUID.
claude-notify mute # Silence everything
claude-notify mute safe-seal # Silence one session
claude-notify status # Check what's muted
claude-notify unmute # Re-enable allMute state is stored as files in ~/.config/claude-notify/muted/.
--user(default) — writes hooks to~/.claude/settings.json, applies to all projects--project— writes hooks to.claude/settings.jsonin the current directory, applies to this project only
Both scopes write backend credentials to ~/.config/claude-notify/config.toml.
~/.config/claude-notify/config.toml:
backends = ["desktop"] # or ["telegram"], ["slack"], ["desktop", "slack"], etc.
# Optional: filter which events trigger notifications (defaults to all)
# events = ["permission_prompt", "idle_prompt", "elicitation_dialog", "stop", "task_completed"]
[telegram]
bot_token = "123456:ABC-DEF..."
chat_id = "123456789"
[slack]
webhook_url = "https://hooks.slack.com/services/T.../B.../xxx"
[discord]
webhook_url = "https://discord.com/api/webhooks/123/abc"
[whatsapp]
phone_number_id = "123456789"
access_token = "EAAxxxxxxx"
recipient = "14155551234"
[openclaw]
gateway_url = "http://localhost:3000"
token = "my-gateway-token"
target = "+15555550123"
channel = "whatsapp" # optional: whatsapp, telegram, discord, etc.
[email]
from = "claude-notify@example.com"
to = "you@example.com"
smtp_host = "smtp.example.com"
smtp_port = 587
smtp_username = "user"
smtp_password = "password"
[ntfy]
topic_url = "https://ntfy.sh/my-claude-topic"
[pushbullet]
api_token = "o.xxxxxxxxxxxxxxxxxxxxx"
[teams]
webhook_url = "https://xxx.webhook.office.com/webhookb2/..."
[webhook]
url = "https://example.com/notify" # unnamed webhook
[webhook.ha-appletv] # named instance
url = "http://homeassistant:8123/api/webhook/claude-notify"
[webhook.ha-direct] # named instance with auth headers
url = "http://homeassistant:8123/api/services/notify/apple_tv"
[webhook.ha-direct.headers]
Authorization = "Bearer YOUR_HA_LONG_LIVED_TOKEN"Env vars override config file values.
| Variable | Purpose | Example |
|---|---|---|
NOTIFY_BACKEND |
Active backend(s), comma-separated | desktop, slack,discord |
NOTIFY_EVENTS |
Event filter, comma-separated | permission_prompt,idle_prompt |
TELEGRAM_BOT_TOKEN |
Token from @BotFather | 123456:ABC-DEF... |
TELEGRAM_CHAT_ID |
User's chat ID | 123456789 |
SLACK_WEBHOOK_URL |
Slack Incoming Webhook URL | https://hooks.slack.com/services/... |
DISCORD_WEBHOOK_URL |
Discord webhook URL | https://discord.com/api/webhooks/... |
EMAIL_FROM |
Sender email address | claude-notify@example.com |
EMAIL_TO |
Recipient email address | you@example.com |
EMAIL_SMTP_HOST |
SMTP server hostname | smtp.example.com |
EMAIL_SMTP_PORT |
SMTP port (default 587) | 587 |
EMAIL_SMTP_USERNAME |
SMTP username | user |
EMAIL_SMTP_PASSWORD |
SMTP password | password |
NTFY_TOPIC_URL |
ntfy topic URL | https://ntfy.sh/my-topic |
PUSHBULLET_API_TOKEN |
Pushbullet API token | o.xxxxxxxxxxxxxxxxxxxxx |
TEAMS_WEBHOOK_URL |
Teams webhook URL | https://xxx.webhook.office.com/... |
WHATSAPP_PHONE_NUMBER_ID |
WhatsApp Business phone number ID | 123456789 |
WHATSAPP_ACCESS_TOKEN |
Meta permanent access token | EAAxxxxxxx |
WHATSAPP_RECIPIENT |
Recipient phone (international format) | 14155551234 |
OPENCLAW_GATEWAY_URL |
OpenClaw Gateway URL | http://localhost:3000 |
OPENCLAW_TOKEN |
Gateway Bearer token | my-gateway-token |
OPENCLAW_TARGET |
Target destination | +15555550123 |
OPENCLAW_CHANNEL |
Delivery channel (optional) | whatsapp |
WEBHOOK_URL |
Generic webhook URL | https://example.com/notify |
To silence noisy events like "Response Complete":
events = ["permission_prompt", "idle_prompt", "elicitation_dialog", "task_completed"]No configuration needed — just run claude-notify setup desktop. Uses osascript on macOS, notify-send on Linux, and PowerShell toast notifications on Windows.
- In your Discord server, go to a channel's settings → Integrations → Webhooks
- Create a new webhook and copy the URL
- Run
claude-notify setup discord <WEBHOOK_URL>
- Pick a topic name at ntfy.sh (or use your own ntfy server)
- Subscribe to the topic on your phone via the ntfy app
- Run
claude-notify setup ntfy https://ntfy.sh/my-claude-topic
- In Teams, create an Incoming Webhook via Workflows (Power Automate) — the legacy Office 365 connectors are deprecated
- Copy the webhook URL
- Run
claude-notify setup teams <WEBHOOK_URL>
Configure SMTP credentials for email notifications. Uses STARTTLS on port 587 by default.
claude-notify setup email sender@example.com recipient@example.com smtp.example.com username passwordFor Gmail, use an App Password with smtp.gmail.com.
Point notifications at any HTTP endpoint. The webhook receives a POST with JSON:
{"title": "🔔 Permission Required", "body": "Session: safe-seal ...", "text": "full plain text"}Unnamed (single): claude-notify setup webhook <URL>
Named instances: claude-notify setup webhook <NAME> <URL> — use webhook.<name> in backends:
claude-notify setup webhook ha-appletv http://homeassistant:8123/api/webhook/claude-notify
claude-notify setup webhook zapier https://hooks.zapier.com/hooks/catch/123/abc
claude-notify use webhook.ha-appletv,webhook.zapier # use bothCustom headers (e.g. auth tokens) can be added manually to config.toml:
[webhook.ha-direct.headers]
Authorization = "Bearer YOUR_TOKEN"Any 2xx response is treated as success.
- Go to Pushbullet Settings and create an Access Token
- Run
claude-notify setup pushbullet <API_TOKEN>
- Go to Slack API: Incoming Webhooks and create a new app (or use an existing one)
- Enable Incoming Webhooks and add one to your desired channel
- Copy the webhook URL
- Run
claude-notify setup slack <WEBHOOK_URL>
OpenClaw is a self-hosted gateway that connects chat apps (WhatsApp, Telegram, Discord, iMessage, etc.) to AI agents. Use it to route claude-notify notifications through any channel OpenClaw supports.
- Install and run the OpenClaw Gateway
- Get your Gateway URL and Bearer token
- Run
claude-notify setup openclaw <GATEWAY_URL> <TOKEN> <TARGET> - Optionally specify a delivery channel:
--channel whatsapp
claude-notify setup openclaw http://localhost:3000 my-token +15555550123
claude-notify setup openclaw http://localhost:3000 my-token +15555550123 --channel whatsapp- Create a Meta Developer account and create an app with WhatsApp
- In the WhatsApp section, get your Phone Number ID and generate a permanent access token
- Run
claude-notify setup whatsapp <PHONE_NUMBER_ID> <ACCESS_TOKEN> <RECIPIENT_PHONE>
The recipient phone number should be in international format without + (e.g. 14155551234).
- Message @BotFather on Telegram, send
/newbot, and follow the prompts to get a bot token - Message @userinfobot to get your chat ID
- Run
claude-notify setup telegram <BOT_TOKEN> <CHAT_ID>
Generated by claude-notify setup (or auto-registered by the plugin), or add manually to ~/.claude/settings.json:
{
"hooks": {
"Notification": [{
"matcher": "permission_prompt|idle_prompt|elicitation_dialog",
"hooks": [{ "type": "command", "command": "claude-notify", "async": true }]
}],
"Stop": [{
"hooks": [{ "type": "command", "command": "claude-notify", "async": true }]
}],
"TaskCompleted": [{
"hooks": [{ "type": "command", "command": "claude-notify", "async": true }]
}]
}
}All hooks use async: true so they never block Claude Code.
Claude Code Event → Hook (async) → claude-notify → Notifier trait → Desktop / Telegram / Slack / Discord / Ntfy / Pushbullet / Teams / Webhook / Email / WhatsApp / OpenClaw
The notification backend is abstracted behind a Notifier trait. Adding new backends requires implementing a single trait:
pub trait Notifier {
fn send(&self, message: &str) -> Result<(), Box<dyn std::error::Error>>;
fn name(&self) -> &str;
}# Dry run a permission prompt
echo '{"session_id":"abc123","cwd":"/tmp/test","hook_event_name":"Notification","notification_type":"permission_prompt","tool_name":"Bash","tool_input":{"command":"npm install"}}' | claude-notify --dry-run
# Dry run a stop event with last message
echo '{"session_id":"abc123","cwd":"/tmp/test","hook_event_name":"Stop","last_assistant_message":"I fixed the bug in the login handler."}' | claude-notify --dry-run
# Dry run a task completed event
echo '{"session_id":"abc123","cwd":"/tmp/test","hook_event_name":"TaskCompleted","task_subject":"Fix auth bug","teammate_name":"implementer"}' | claude-notify --dry-runThis project was entirely designed, coded, and documented by AI (Claude, by Anthropic) using Claude Code. A human provided the requirements and direction — all implementation was AI-generated.
MIT