Notifications for AI coding agents: Claude Code and Codex side by side
The short answer
Claude Code and Codex both alert you through two hook events of the same name: Stop
when a turn ends and PermissionRequest when approval is needed. After that they
differ. Claude Code adds a Notification event with an idle reminder, which Codex does
not have. Codex adds a one-line notify setting and a built-in alert that falls back to
the terminal bell, where Claude Code stays silent in most terminals. Their hook files share a shape,
so one small script can serve both.
Or let a light show it
Alerts tell you about one moment on one screen. With two agents running, the harder question is what each is doing now, and that is where a light fits: it shows the current state of both from across the room and adds no ping.
What it does
AC Bridge turns the smart lights and plugs you already own (Hue, LIFX, Govee, WiZ, Home Assistant and more) into a status light for Claude Code and Codex, in the same app and on the same lamps. In the example colours from our homepage, the lamp breathes blue while the agent works, flashes red when it needs permission and turns green when it has finished; you pick the colours, and give each project its own lamp or let one lamp follow several.
What it follows
-
Claude Code: can trigger all 29 states, through hooks that come with its plugin, so there is
nothing to paste into your settings files. Needs permission comes from the
Notificationhook. -
Codex: drives 19 of the 29 states. Setup adds its entries to
~/.codex/hooks.jsonand keeps the ones already there; type/hooksonce to trust them. Needs permission comes fromPermissionRequest. - Both at once: a folder can hold one Claude profile and one Codex profile, and each names its own devices, so the two can use different lamps. On a shared lamp, the most recent session wins by default.
- Hooks you wrote yourself keep running alongside it.
What it costs
One plan: a 7-day free trial with no card needed, then £2.99 a month if you add a card to keep going; without one the trial just ends and nothing is charged. Cancel any time from your account. It works with the Claude Code or Codex you already run, on Windows, macOS or Linux. There is no API key to buy.
What it collects
LAN devices are driven straight from your machine and their keys never leave it; your account, settings, device list, usage counts and session states sync through our servers. Your prompts, code and session transcripts are never collected. Privacy policy.
Try it on your own lights Start the 7-day free trial, or read the setup docs and the status light guide first.
What can Claude Code and Codex notify you about?
For every method on one agent, sound and phone included, read the Claude Code notifications guide or the Codex notifications guide. This is the side-by-side, as the Claude Code hooks reference and terminal guide, the Codex hooks page and advanced configuration stood on the date above.
| You want to know | Claude Code | Codex |
|---|---|---|
| A turn finished | Stop | Stop, or notify on agent-turn-complete |
| It wants approval | PermissionRequest, when the prompt appears | PermissionRequest, when Codex is about to ask |
| Approval is waiting and you look away | Notification with permission_prompt, after about six seconds without typing | No hook; the built-in alert's approval-requested |
| It has gone quiet and waits for you | Notification with idle_prompt, about 60 seconds after it finishes | No event |
| A turn failed on an API error | StopFailure, which runs instead of Stop | No event |
| You interrupted a turn | No event; Stop does not run | Interrupt |
| The session ended | SessionEnd | SessionEnd, which never runs in the background |
| Run a program with no hook | No setting; use a Stop hook | notify in ~/.codex/config.toml |
Built in: Claude Code
- A desktop notification by default in Ghostty, Kitty and iTerm2; iTerm2 needs its alert settings turned on first.
- Nothing by default in most other terminals, until you set
"preferredNotifChannel": "terminal_bell"in~/.claude/settings.json. - It fires when you appear to be away from the terminal.
Built in: Codex
tui.notificationsis on by default and fires while the terminal is unfocused;notification_conditionset toalwayschanges that.- In its default
automode it sends OSC 9 where the terminal seems to support it, and rings the bell elsewhere. - Going by the Codex source, it also fires when Codex asks you a question, which no hook covers.
Set up one alert for Claude Code and Codex
Both hook files nest the same way: an event, a matcher group, then a list of handlers. Both also run a handler in the session's working directory. So one script can do the work, and each agent's file only passes in its name and what happened.
The script, for macOS and Linux
Save it as ~/.local/bin/agent-notify. It sends all its output to
/dev/null on purpose: a Codex Stop hook must print JSON or nothing.
~/.local/bin/agent-notify
#!/bin/sh
# One alert for Claude Code and Codex. Usage: agent-notify AGENT WHAT
agent="${1}"
what="${2}"
text="$what in $(basename "$PWD")"
case "$(uname -s)" in
Darwin) osascript -e 'on run argv' \
-e 'display notification (item 1 of argv) with title (item 2 of argv)' \
-e 'end run' "$text" "$agent" ;;
*) notify-send "$agent" "$text" ;;
esac >/dev/null 2>&1
exit 0
Claude Code: three entries
Merge this into ~/.claude/settings.json. It uses PermissionRequest rather
than the permission_prompt matcher, which would alert you twice for one prompt.
~/.claude/settings.json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.local/bin/agent-notify 'Claude Code' 'Finished'",
"async": true
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "~/.local/bin/agent-notify 'Claude Code' 'Needs approval'",
"async": true
}
]
}
],
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "~/.local/bin/agent-notify 'Claude Code' 'Waiting for you'",
"async": true
}
]
}
]
}
}
Codex: two entries
Merge this into ~/.codex/hooks.json. There is no third entry, because Codex has no
event for it. Codex skips both entries until you trust them.
~/.codex/hooks.json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.local/bin/agent-notify 'Codex' 'Finished'",
"async": true
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "~/.local/bin/agent-notify 'Codex' 'Needs approval'",
"async": true
}
]
}
]
}
}
On Windows
The script above is for macOS and Linux, but the same plan holds. Write one PowerShell script that
takes the same two arguments, set "shell": "powershell" on each Claude Code entry, and
add commandWindows beside command in each Codex entry.
-
Make it runnable
Run
mkdir -p ~/.local/binbefore you save the file, andchmod +x ~/.local/bin/agent-notifyafter. -
Try it by hand
Run
~/.local/bin/agent-notify 'Codex' 'Finished'in a project folder. No alert here means the script is at fault, not the hooks. -
Trust it in Codex
Type
/hooksinside Codex and trust the two new entries. -
Accept the folder in Claude Code
It holds back every settings-file hook, your own included, until you accept the workspace trust dialog for that folder.
Notifications when you run two coding agents at once
With one agent, an alert means that agent. With two, the alert also has to say which one, and the number of alerts doubles.
Which one wants you
A bell only says that something happened. The script puts the agent in the title and the folder in the text, so "Needs approval in api" under Codex tells you where to go before you switch windows.
Both in one folder
Nothing stops the two agents working in the same project, and the title is what separates them
there. Keep the entries in your home folder files, as above, and they cover every project; the
project-level .claude/settings.json and .codex/hooks.json are for hooks a
single repo needs.
The same alert twice
Hooks run alongside the built-in alerts. To keep only the script, set
notifications = false under [tui] in
~/.codex/config.toml, and set preferredNotifChannel to
notifications_disabled in Claude Code.
Too many alerts
Stop fires on every finished turn, in both agents. If two busy sessions turn that into
noise, delete the Stop entries and keep PermissionRequest, so you only hear
about work that is stuck.