How to play a sound when Claude Code finishes or needs input
To play a sound when Claude Code finishes or needs you, add a Stop hook and a Notification hook to your settings.json file, and have each run an audio player on a short sound file. The sounds in this guide are CC0, so they need no credit.
Last updated:
Example tracks
These are real catalog tracks. The credit line under each row is the one Uncommon Ear generates.
-
CreatorAssets UI.
0.7 s -
josepharaoh99 UI and foley.
0.3 s -
Kenney UI.
0.2 s
Steps
Save the sound files
Pick one short sound for each event. The three examples below are the ones on the coding agents page. Save them in a folder such as ~/.claude/sounds as done.wav and needs-input.wav, and error.wav if you want a third sound for failures.
Test the player command
Before you touch any settings, run the command in your terminal. On macOS, afplay comes with the system. On Linux, use a player such as paplay or aplay instead. If you hear nothing here, Claude Code will not play it either.
Test the player commandafplay "$HOME/.claude/sounds/done.wav"Choose where the hooks live
Open ~/.claude/settings.json to hear the sounds in every project. Open .claude/settings.json in a project folder to hear them in that project only, and to share them with the team if you commit the file. Use .claude/settings.local.json for a project setting that stays on your machine.
Add a hook for when Claude finishes
The Stop event fires when Claude finishes responding. Stop does not support a matcher, so the hook runs after every turn. If your file already has a hooks key, add Stop inside it instead of replacing the object.
Add a hook for when Claude finishes{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "afplay \"$HOME/.claude/sounds/done.wav\"" } ] } ] } }Add a hook for when Claude needs you
The Notification event fires when Claude Code sends a notification. Its matcher picks the notification type. The permission_prompt type fires when Claude needs you to approve something and the prompt has waited about six seconds. The idle_prompt type fires when Claude finished about 60 seconds ago and you have not typed since.
Add a hook for when Claude needs you{ "hooks": { "Notification": [ { "matcher": "permission_prompt|idle_prompt", "hooks": [ { "type": "command", "command": "afplay \"$HOME/.claude/sounds/needs-input.wav\"" } ] } ] } }Add a hook for errors
If you want a third sound, add a StopFailure hook. It fires when a turn ends because of an API error, and its matcher filters by error type.
Add a hook for errors{ "hooks": { "StopFailure": [ { "matcher": "rate_limit|overloaded|server_error", "hooks": [ { "type": "command", "command": "afplay \"$HOME/.claude/sounds/error.wav\"" } ] } ] } }Check that Claude Code loaded the hooks
In Claude Code, enter /hooks. It opens a read-only list of your hooks and shows where each one comes from. Then ask Claude to run a command that needs permission and look away from the terminal for a few seconds.
Stop a long sound from blocking Claude
Command hooks block by default, so a long sound holds up the hook until it ends. Keep sounds under a couple of seconds, or set async to true to run the command in the background.
Stop a long sound from blocking Claude{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "afplay \"$HOME/.claude/sounds/done.wav\"", "async": true } ] } ] } }
Common mistakes
- Replacing the whole hooks object. If the file already has hooks, add your events as siblings of the existing ones.
- Adding a matcher to Stop. The event has no matcher support, so the matcher is ignored.
- Leaving the Notification matcher empty. An empty matcher fires on every notification type, including ones you do not need a sound for.
- Expecting the sound on your laptop when Claude Code runs over SSH. The hook runs on the machine where Claude Code runs.
- Using a long sound or a long track. Pick a sound well under two seconds, so you hear which event fired before the next one starts.
- Skipping the player test. If the command fails in your terminal, the hook fails the same way.