Play a sound when an AI coding agent finishes or needs your attention, but only when its
terminal window is not focused.
No noise while you are watching it work, a bell when you have switched away.
Here is a Medium article about this project.
Agents:
Claude Code,
Codex, and
opencode
Install in one command:
# Linux or Mac
git clone https://github.com/Helias/ai-notify.git && cd ai-notify && ./install.sh
# Windows
git clone https://github.com/Helias/ai-notify.git; cd ai-notify; powershell -ExecutionPolicy Bypass -File .\install.ps1...or you can ask your agent to install it for you 😉
On Linux and macOS, notify-if-unfocused.sh detects the OS and the
currently focused window, walks up its own process tree, and plays a sound only when none of
its ancestor processes own the focused window. On Windows,
notify-if-unfocused.ps1 does the same with the Win32 API.
Linux: focused window via xdotool; sound via the first available player, tryingpaplay,pw-play,ffplay, thenaplay.macOS: frontmost app via
osascript, sound viaafplay.Windows: foreground window via
GetForegroundWindow/GetWindowThreadProcessId(PowerShell + Win32); sound via a built-in notification.wav(System.Media.SoundPlayer), falling back to a system sound.conhost.exe/OpenConsole.exewindows are resolved to their owning shell so classic consoles and Windows Terminal both work.
install.sh checks for these and offers to install any that are missing using your package
manager. You can also install them yourself:
- Linux:
xdotool(sudo apt install xdotool). Works on X11; Wayland support depends onxdotoolcompatibility. For sound you almost certainly already have a player (paplayorpw-playship with the PulseAudio/PipeWire desktop stack); only if you have none ofpaplay,pw-play,ffplay, oraplaydo you need to install one, e.g.sudo apt install ffmpeg. - macOS: no extra tooling,
osascriptandafplayship with the system. - Windows: no extra tooling.
notify-if-unfocused.ps1andinstall.ps1use only built-in PowerShell (5.1+, ships with Windows) and the Win32 API — nojq,xdotool, or sound player to install. If your environment restricts scripts, the installer/hook commands already pass-ExecutionPolicy Bypass. jqis required byinstall.sh(Linux/macOS only). Install it withsudo apt install jqorbrew install jq. The Windows installer (install.ps1) does its JSON merging natively and needs nojq.
Claude Code
Merge the hooks (and preferredNotifChannel) from templates/claude/settings.json
into your ~/.claude/settings.json. It fires the script on Stop and on permission/idle
notifications.
{
"preferredNotifChannel": "notifications_disabled",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash [COMMAND_PATH]/notify-if-unfocused.sh"
}
]
}
],
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "bash [COMMAND_PATH]/notify-if-unfocused.sh"
}
]
}
]
}
}On Windows, use
templates/claude/settings.windows.json
instead (same structure, with the command set to
powershell -NoProfile -ExecutionPolicy Bypass -File "[COMMAND_PATH]/notify-if-unfocused.ps1").
.\install.ps1 claude does this merge for you.
Codex
Copy templates/codex/hooks.json to ~/.codex/hooks.json (or merge
its hooks into your existing one). It fires the script on Stop.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "[COMMAND_PATH]/notify-if-unfocused.sh",
"timeout": 5
}
]
}
]
}
}On Windows, use
templates/codex/hooks.windows.json
instead (command set to powershell -NoProfile -ExecutionPolicy Bypass -File "[COMMAND_PATH]/notify-if-unfocused.ps1").
.\install.ps1 codex does this for you.
opencode
Two files under ~/.config/opencode/:
-
templates/opencode/opencode.jsoncenables the built-in attention notification: -
templates/opencode/plugin/notify.jsruns the script onsession.idle. Remember to replace[COMMAND_PATH]inside it.On
Windows, use
templates/opencode/plugin/notify.windows.jsinstead — it invokesnotify-if-unfocused.ps1viapowershell..\install.ps1 opencodeinstalls it for you. (opencode.jsoncis identical on every platform.)

{ "$schema": "https://opencode.ai/config.json", "tui": { "attention": { "notify": true, "sound": true, }, }, }