How to get a notification when Codex finishes or needs approval
The short answer
Codex already notifies you: tui.notifications is on by default and fires when the
terminal is not focused, including when Codex asks you a question. For a sound, a desktop toast
or a phone push in any terminal, add a Stop hook for every finished turn and a
PermissionRequest hook for approval requests to ~/.codex/hooks.json,
then trust them once with /hooks. Codex has no hook for "needs input", but the
built-in alert covers its questions. For Claude Code, see the
Claude Code notifications guide.
Checked against the Codex docs on .
On this page: which signal fires when · built-in notifications · notify · hooks · your phone · the app and the IDE · when one does not fire · questions · a light instead.
Which Codex signal fires when
Codex has four signals you can use in the terminal. They differ in when they fire and in whether they care if you are looking at the terminal.
| Signal | Fires when | Only when the terminal is unfocused? |
|---|---|---|
tui.notifications |
Codex finishes a turn, asks for approval or asks you a question (all events when set to true) |
By default; set notification_condition = "always" to change it |
notify |
A turn completes (agent-turn-complete, the only event) |
No |
Stop hook |
Codex finishes responding at the end of a turn | No |
PermissionRequest hook |
Codex is about to ask for approval. It does not run for commands that need none. | No |
The gotcha
Codex has no idle reminder and no needs-input hook event. Its hook events are Stop,
PermissionRequest and others such as PreToolUse, but nothing that means
"waiting for you". The built-in tui.notifications alert is the one signal that also
covers a question.
1. Built-in notifications: tui.notifications
Nothing to install. tui.notifications defaults to true, and
tui.notification_condition defaults to unfocused, so Codex alerts you
only when the terminal is not the window you are looking at. Set the condition to
always to be alerted regardless. tui.notification_method picks how:
auto (the default) prefers an OSC 9 desktop notification, a terminal escape sequence
some terminals turn into a desktop alert, and falls back to the terminal bell; osc9
or bel forces one. In ~/.codex/config.toml:
[tui]
notifications = true
notification_method = "auto"
notification_condition = "always"
Keep notifications = true rather than a list of event types. The setting also accepts
a list such as ["agent-turn-complete", "approval-requested"], but a list that leaves
the question event out turns question alerts off.
In practice, terminals without OSC 9 desktop support, such as Windows Terminal and the VS Code terminal, get the bell rather than a desktop alert. If you want a toast there, use a hook (section 3). Reference: configuration reference.
2. notify: run a program when a turn completes
notify runs an external program whenever Codex emits a supported event, and the only
supported event is agent-turn-complete. The program receives one JSON argument,
appended as the last argument, with type, thread-id,
turn-id, cwd, input-messages and
last-assistant-message. Put it in your own ~/.codex/config.toml, above
the first [table] line, or TOML files it under that table. Codex ignores
notify in a project's .codex/config.toml and prints a startup warning.
notify = ["notify-send", "Codex"]
That is the example from Codex's own configuration guide. For a tidier message, point
notify at a small script that reads last-assistant-message from that
JSON argument; the
advanced configuration guide
has the details. notify is the older mechanism: hooks are the newer, broader option
and the one to start with.
3. Codex hooks: a notification on Stop and PermissionRequest
Hooks are on by default. Codex
reads them from ~/.codex/hooks.json, ~/.codex/config.toml,
<repo>/.codex/hooks.json and <repo>/.codex/config.toml;
project-local hooks load only when that project's .codex/ layer is trusted. This
file registers a notification for a finished turn and for an approval request:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "notify-send 'Codex' 'Finished' >/dev/null 2>&1",
"async": true
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "notify-send 'Codex' 'Needs your approval' >/dev/null 2>&1",
"async": true
}
]
}
]
}
}
-
Keep stdout empty on Stop.
Stopexpects JSON on stdout when it exits 0, and plain text output is invalid for that event. Exit 0 with no output counts as success, which is why the commands above send their output to/dev/null. - PermissionRequest runs only when approval is needed, such as a shell escalation or a managed-network approval. A command that needs no approval never triggers it.
-
Async means background.
"async": trueruns the command in the background, so a slow notifier never holds Codex up. A background hook cannot block, approve or rewrite anything, which is what you want from a notifier. -
Windows. Add a
commandWindowsstring next tocommandfor a Windows-only override. - Other hooks keep running. When several hooks match the same event, they all run, concurrently, so a notifier can sit beside hooks you already have.
Trust a new hook once with /hooks
Before a non-managed hook can run, Codex requires you to review and trust the exact hook
definition. New or changed hooks are marked for review and skipped until trusted, and Codex prints
a startup warning telling you to open /hooks. Start Codex, type /hooks,
review each hook and trust it. Change a command later and it needs trusting again. The
hooks page
explains the review step.
4. A notification on your phone
For the ChatGPT desktop app, the official path is the ChatGPT mobile app's remote connection to a Mac or Windows computer running the desktop app, described in the docs as a way to "get notified when ChatGPT completes a task or needs your attention". See remote connections.
For the terminal CLI, post to a push service from a hook. ntfy is a free one: subscribe to a topic in its app, then publish to that topic with curl. There is no sign-up, so the topic name works like a password. Pick one nobody could guess.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -o /dev/null -d \"Codex finished\" ntfy.sh/your-hard-to-guess-topic",
"async": true
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -o /dev/null -d \"Codex needs your approval\" ntfy.sh/your-hard-to-guess-topic",
"async": true
}
]
}
]
}
}
-o /dev/null matters: ntfy replies with JSON, and Stop parses its
stdout. Do not use notify = ["curl", ...] instead. notify appends the
event's JSON payload as the last argument, so curl would receive it as one more thing to fetch.
Trust the hooks in /hooks as in section 3.
In the ChatGPT desktop app, on the web and in the IDE extension
- The ChatGPT desktop app (the docs' current name for the Codex app) has its own turn-completion alerts: never, only in the background, or always. Permission requests and questions have separate toggles.
- On the web, Settings, Notifications offers push, email or SMS channels.
-
The IDE extension has no separate notification controls. Configure
notifyon the connected Codex host, as in section 2.
The full list is on the notifications page.
When a Codex notification does not fire
-
The hook is not trusted. A new or changed hook is skipped until you review it
in
/hooks. Codex prints a startup warning while any hook waits. -
notifysits in a project config. Codex ignores it there. Move it to~/.codex/config.toml, above the first table. -
The terminal is focused. The default
notification_conditionisunfocused. Set it toalwaysto be alerted while you watch. - Your terminal has no OSC 9 support, so you get only the bell. Check that the bell is switched on, or use a hook for a real toast.
-
A Stop hook prints plain text. The event wants JSON or nothing on stdout.
Send the notifier's output to
/dev/null, and keep-o /dev/nullon curl. -
Hooks are turned off.
[features] hooks = falseinconfig.tomlswitches every hook off. Remove it or set it totrue.
Questions people ask
Does Codex notify me when it finishes?
Yes. The built-in tui.notifications alert is on by default and fires when the
terminal is unfocused. For a toast or sound every time, add a Stop hook or a
notify line, which fires on agent-turn-complete.
Does Codex notify me when it needs approval?
Yes. A PermissionRequest hook runs when Codex is about to ask for approval, and the
built-in alert can cover it too. The hook does not run for commands that need no approval, and
it needs trusting in /hooks first.
Does Codex tell me when it asks a question?
Through the built-in alert, yes: with tui.notifications = true Codex also alerts you
when it asks a question. There is no needs-input hook event, and a filter list that omits those
events turns question alerts off.
Why did my Codex hook not run?
Most often it has not been trusted. Codex skips a new or changed hook until you open
/hooks and trust it. Also check that [features] hooks is not
false and that the file is valid JSON.
Why do I get a bell instead of a desktop notification?
In auto mode Codex prefers OSC 9 and falls back to the bell. Windows Terminal and the
VS Code terminal get the bell. Use a Stop hook with notify-send,
terminal-notifier or a similar notifier for a desktop alert.
Should I use notify or a hook?
Start with a hook. Hooks are the newer, broader mechanism and cover both a finished turn
(Stop) and an approval request (PermissionRequest). notify
fires on agent-turn-complete only, and only from your user config.
How do I turn Codex notifications off?
Set tui.notifications = false for the built-in alert, delete the notify
line, and remove any notifier entries from hooks.json. Setting
[features] hooks = false switches off every hook, not only notifiers.
Or let a light show it
A sound needs you at the desk and listening, and a toast needs you looking at the screen. A light works from across the room, with headphones on, and adds no extra ping.
AC Bridge turns the smart lights and plugs you already own (Hue,
LIFX, Govee, WiZ, Home Assistant and more) into a status light for Codex and Claude Code. On
Codex, setup adds its entries to ~/.codex/hooks.json and keeps the hooks already
there; type /hooks once inside Codex to trust them. 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.
On Codex, needs permission lights up the moment Codex asks for approval, because it follows the
PermissionRequest hook. Codex drives 19 of the 29 states. Your own
Stop or PermissionRequest notifier keeps running alongside it, because
every matching hook runs. See
How the Claude Code status light works for the Claude Code
side, and the Claude Code notifications guide for
its free methods.
One plan: a 3-day free trial with your card taken up front, then £2.99 a month, charged when the trial ends. Cancel any time from your account; cancel before the trial ends and you pay nothing. It works with the Claude Code or Codex you already run, on Windows, macOS or Linux. There is no API key to buy.
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 3-day free trial, or read the setup docs and the status light guide first.