Audio notifications for Claude Code. Hear a sound when Claude completes a task or needs your input.
claudeding is not affiliated with or endorsed by Anthropic.
# Install globally
npm install -g @byricky/claudeding
claudeding setup
# Or use npx
npx @byricky/claudeding setupOnce set up, you'll hear:
- A completion sound when Claude finishes a task
- A feedback sound when Claude is waiting for your input
- An error sound when a tool fails
You'll also see a system notification showing which project triggered it.
- Focus detection: No sound when you're looking at the terminal (you can already see it)
- AFK detection: Plays sound if you've been idle 30+ seconds, even if terminal is focused
- Debouncing: Multiple Claude instances won't spam you with sounds
- Random messages: Fun notifications with emojis like "π All done!" and "π Need your input!"
- Custom messages: Set your own notification text
- Volume control: Adjust notification volume (0-100)
- Quiet hours: Automatically mute sounds during specified hours
- Snooze: Temporarily pause sounds (
claudeding snooze 30m) - Menu bar widget: Quick controls from your menu bar (macOS)
- Per-project sounds: Different sounds for different projects
- System DND respect: Optional integration with macOS Focus mode
- Webhooks: Send notifications to Slack or Discord
- Usage stats: Track your Claude usage patterns (opt-in)
Setup also adds instructions to your ~/.claude/CLAUDE.md so Claude knows how to control notifications when you ask (e.g., "mute the dings").
Installs hooks into Claude Code, creates config, and adds Claude instructions.
claudeding setup
# With custom sounds
claudeding setup --complete-sound ~/sounds/done.wav --feedback-sound ~/sounds/attention.wavRemoves claudeding hooks and instructions from Claude Code.
claudeding uninstallQuick overview of current state.
claudeding statusExample output:
claudeding status
State: π Active
Volume: 100%
Hooks:
Complete (Stop): β
Feedback (Notification): β
Error (ToolFailure): β
Thinking (UserPrompt): β
Features:
Skip when focused: on
AFK override: 30s
Quiet hours: off
Webhooks: 2 configured
Interactive settings menu with all configuration options.
claudeding settingsFeatures:
- Volume control with test
- Sound picker
- Preview all sounds
- Toggle focus detection, AFK, quiet hours, DND
- Configure webhooks (Slack/Discord)
- Set custom notification messages
- Enable/disable easter eggs
Toggle sound mute (notifications still show).
claudeding mute # Toggle mute on/off
claudeding mute --on # Mute sounds
claudeding mute --off # Unmute soundsInteractive TUI to preview and select from bundled sounds.
claudeding soundsShows current configuration and hook status.
claudeding configPlays a sound manually. Useful for testing.
claudeding play complete
claudeding play feedback
claudeding play error
# Bypass focus detection (plays even when terminal is focused)
claudeding play complete --forceRun diagnostics to verify setup.
claudeding doctorEnable or disable specific event sounds.
claudeding disable error # Stop playing error sounds
claudeding enable error # Re-enable error soundsTemporarily pause all sounds.
claudeding snooze 30m # Snooze for 30 minutes
claudeding snooze 2h # Snooze for 2 hours
claudeding snooze # Check snooze status
claudeding snooze --off # Cancel snoozeStart a menu bar widget (macOS only). Shows status and quick controls.
claudeding trayFeatures:
- Live status icon: π idle, β complete, π needs input, β error, π€ snoozing, π muted
- Mute/unmute toggle
- Quick snooze buttons (15m, 30m, 1h, 2h)
- Test sounds
- Native macOS menu
- Runs in background
View usage statistics (off by default to save resources).
claudeding stats --on # Enable logging
claudeding stats # View stats
claudeding stats --off # Disable loggingExample output:
claudeding Stats
Events:
Today: 12 complete, 8 feedback, 2 errors
This week: 84 complete, 45 feedback, 7 errors
This month: 312 complete, 201 feedback, 23 errors
All time: 536 total events
Insights:
Avg time between feedback: 14m
Error rate: 4.3%
Peak coding hour: 2PM
Top Projects:
1. my-app (234 events)
2. api-server (156 events)
3. docs (89 events)
History file: 42.1 KB (536 events)
Config is stored at ~/.claudeding.json:
{
"sounds": {
"complete": null,
"feedback": null,
"error": null
},
"notify": true,
"mute": false,
"volume": 100,
"skipWhenFocused": true,
"afkTimeout": 30,
"respectDnd": false,
"useProjectConfig": false,
"logStats": false,
"quietHours": {
"enabled": false,
"start": "22:00",
"end": "08:00"
},
"webhooks": [],
"customMessages": {
"complete": ["Done!", "All set!"],
"feedback": ["Your turn!"],
"error": ["Oops!"]
}
}| Option | Description |
|---|---|
sounds.complete |
Name of bundled sound or path to custom WAV/MP3. null = default |
sounds.feedback |
Name of bundled sound or path to custom WAV/MP3. null = default |
sounds.error |
Name of bundled sound or path to custom WAV/MP3. null = default |
notify |
Show system notifications (true/false) |
mute |
Mute all sounds (true/false) |
volume |
Volume level 0-100 (default: 100) |
skipWhenFocused |
Skip sounds when terminal is focused (true/false) |
afkTimeout |
Seconds of idle time before playing sound even when focused. Set to 0 to disable AFK detection |
respectDnd |
Skip sounds when system DND/Focus mode is on (true/false, default: false) |
useProjectConfig |
Use .claudeding.json in project root if present (true/false, default: false) |
logStats |
Log events to history file for stats (true/false, default: false) |
quietHours.enabled |
Enable quiet hours (true/false) |
quietHours.start |
Start time in 24-hour format (e.g., "22:00") |
quietHours.end |
End time in 24-hour format (e.g., "08:00") |
webhooks |
Array of webhook URLs (Slack/Discord auto-detected) |
customMessages.complete |
Array of custom completion messages |
customMessages.feedback |
Array of custom feedback messages |
customMessages.error |
Array of custom error messages |
With useProjectConfig: true, you can create a .claudeding.json in any project root to override global settings:
{
"sounds": {
"complete": "chord"
},
"volume": 50
}Send notifications to Slack or Discord when Claude completes tasks or needs input.
claudeding settings
# β Webhooks β Add webhook β paste URLAdd webhook URLs to ~/.claudeding.json:
{
"webhooks": [
"https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
"https://discord.com/api/webhooks/YOUR/DISCORD/WEBHOOK"
]
}Webhook type (Slack/Discord) is auto-detected from the URL. Messages are formatted appropriately for each platform with emoji indicators and project names.
Optional silly features (off by default):
Play Jeopardy theme when Claude starts thinking:
claudeding enable thinkingDisable with claudeding disable thinking.
1% chance of a random fart sound on any notification:
claudeding enable fartsDisable with claudeding disable farts.
| Platform | Audio | Notifications |
|---|---|---|
| macOS | afplay |
terminal-notifier / osascript |
| Linux | paplay / aplay |
notify-send |
| Windows | PowerShell | Toast notifications |
For better notification branding, install terminal-notifier:
brew install terminal-notifierWithout it, notifications show as "Script Editor". With it, they show your terminal's icon (VS Code, iTerm, etc.).
claudeding adds hooks to your Claude Code settings (~/.claude/settings.json):
- Notification hook β plays feedback sound when Claude needs input
- Stop hook β plays completion sound when Claude finishes
- PostToolUseFailure hook β plays error sound when a tool fails
Your existing hooks are preserved. A backup is created at ~/.claude/settings.json.claudeding-backup before any modifications.
If claudeding setup didn't run, didn't finish, or you want to install into a specific scope, edit the settings file directly. Claude Code reads hooks from:
| File | Scope |
|---|---|
~/.claude/settings.json |
All projects (user) |
.claude/settings.json |
Single project (shareable β commit to repo) |
.claude/settings.local.json |
Single project (gitignored) |
Add (or merge into) the top-level "hooks" key:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "claudeding play feedback" }
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "claudeding play complete" }
]
}
],
"PostToolUseFailure": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "claudeding play error" }
]
}
]
}
}Notes, straight from the Claude Code hooks docs:
Stopfires whenever Claude finishes responding. It ignores matchers β you can omitmatcherentirely.Notificationmatchers are optional.""(or omitting) fires on every notification; set to e.g."permission_prompt"or"idle_prompt"to filter.PostToolUseFailurefires after a tool call fails. Setmatcherto a tool name (e.g."Bash") if you want to scope it.
Opt-in extras that claudeding setup does not enable by default:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "claudeding play thinking" }] }
],
"PreToolUse": [
{ "matcher": "", "hooks": [{ "type": "command", "command": "claudeding stop-thinking" }] }
]
}
}Enable them with claudeding enable thinking.
Run claudeding doctor first β it reports what's missing. Then check the usual suspects:
claudedingnot on Claude Code'sPATH. The hook fires, but the command can't be resolved. Test withwhich claudedingfrom a fresh terminal; if it's missing, reinstall globally (npm install -g @byricky/claudeding) or replace"command": "claudeding β¦"with the absolute path.~/.claude/settings.jsonhas invalid JSON. One stray comma and Claude Code skips the file. Validate withnode -e 'JSON.parse(require("fs").readFileSync(process.env.HOME + "/.claude/settings.json","utf8"))'.- Hook entries were added mid-session. Start a new Claude Code session after editing
settings.json. - You're muted / snoozed.
claudeding statusshows both. Fix withclaudeding mute --off/claudeding snooze --off. - Terminal focused + not AFK. By design. Disable with
skipWhenFocused: false, or lower/disableafkTimeoutin~/.claudeding.json. - Quiet hours / system DND. Check
quietHoursandrespectDndin config. - Volume is 0.
claudeding settingsβ Volume.
Same PATH issue as above, 95% of the time. Claude Code's hook shell may not load your interactive shell init (e.g. nvm-managed node not being visible). Fix by using the absolute path to claudeding in the hook command.
Update to the latest version β the tray now runs its focus/idle checks asynchronously with a 10s cache and skips menu rebuilds when nothing has changed. Older versions blocked the Electron main thread every 2 seconds.
If you suspect multiple trays are running:
pgrep -fl "Electron.*src/tray/main\.js"
pkill -f "Electron.*src/tray/main\.js"
claudeding trayThe current build holds a single-instance lock, so duplicate launches exit immediately.
claudeding uninstall # removes only claudeding's hooks
claudeding setup # reinstalls themclaudeding uninstall leaves ~/.claude/settings.json.claudeding-backup in place β restore it with cp ~/.claude/settings.json.claudeding-backup ~/.claude/settings.json if anything got mangled.
MIT