Codex can notify you in four ways: built-in terminal notifications from the CLI, an external notify program that runs after every finished turn, lifecycle hooks such as Stop and PermissionRequest, and notification settings in the ChatGPT desktop app and on the web. For the CLI, TUI notifications are on by default and fire when your terminal is not focused.
OpenAI's Notifications page sums it up: "Their controls and delivery channels vary by surface." This guide covers each one, read from the official docs on 26 October 2026.
Which Codex notification option should you use?
| Option | Where you set it | Fires on | Good for |
|---|---|---|---|
| TUI notifications | [tui] in ~/.codex/config.toml |
Turn complete, approval requested and more | A desktop alert or bell while you work in another window |
notify |
Top level of ~/.codex/config.toml |
agent-turn-complete only |
Desktop notifiers, chat webhooks, CI updates |
| Hooks | hooks.json or [hooks] |
Any lifecycle event, such as Stop or PermissionRequest |
Custom alerts tied to specific events |
| Desktop app settings | Settings in the ChatGPT desktop app | Turn completion, permissions, questions | App users |
| Web settings | Settings > Notifications on the web | Account categories | Push, email or SMS |
The advanced config docs draw the line between the first two: "notify runs an external program (good for webhooks, desktop notifiers, CI hooks)," while tui.notifications "is built in to the TUI and can optionally filter by event type."
How do you configure TUI notifications?
Three keys under [tui] control the built-in alerts. The defaults, per the sample config, are shown in comments:
[tui]
# true (default), false, or a list of event types
notifications = ["agent-turn-complete", "approval-requested"]
# auto (default) | osc9 | bel
notification_method = "auto"
# unfocused (default) | always
notification_condition = "unfocused"
notifications turns alerts on or off, or limits them to certain types. The docs name agent-turn-complete and approval-requested. The TUI source at release rust-v0.164.0 also defines plan-mode-prompt and async-question, which the docs don't list, and groups command approvals, edit approvals and MCP elicitation requests under approval-requested.
notification_method picks how the alert reaches you. The docs explain: "In auto mode, Codex prefers OSC 9 notifications (a terminal escape sequence some terminals interpret as a desktop notification) when the terminal appears to support them, and falls back to BEL (\x07) otherwise." Force osc9 if your terminal supports it, or bel if you only want the terminal bell.
notification_condition decides when alerts fire. The default, unfocused, keeps Codex quiet while you are looking at it. Set always to get an alert every time, which is also handy for testing.
How do you set up the notify program?
notify runs a program of your choice whenever Codex emits a supported event, currently only agent-turn-complete. It takes a command array:
# ~/.codex/config.toml, top level, above any [table] header
notify = ["python3", "/Users/you/.codex/notify.py"]
Two rules matter. First, it must live in your user config. The docs list notify among keys Codex ignores in a project .codex/config.toml, with a startup warning, because project files can't "run machine-local notification/telemetry commands." Second, in TOML any key written after a [table] header belongs to that table, so put notify near the top of the file.
Codex passes a single JSON argument. The docs list these common fields:
type, currentlyagent-turn-completethread-idandturn-idcwd, the working directoryinput-messages, the user messages that led to the turnlast-assistant-message, the final reply text
The sample config includes a commented-out notify = ["notify-send", "Codex"], which suits Linux desktops with notify-send. For more control, a small script can read the payload. This example, not taken from OpenAI's docs, uses jq and notify-send:
#!/usr/bin/env bash
# ~/.codex/notify.sh (make it executable with chmod +x)
payload="$1"
[ "$(printf '%s' "$payload" | jq -r '.type')" = "agent-turn-complete" ] || exit 0
msg=$(printf '%s' "$payload" | jq -r '."last-assistant-message" // "Turn complete"')
notify-send "Codex" "$msg"
OpenAI's own example is a Python script for macOS that calls terminal-notifier with the last message as the title and groups alerts by thread-id. Swap the final command for curl to post to a chat webhook instead.
How do you get notifications from Codex hooks?
Hooks give you more events than notify. The hooks docs list Stop, which runs when a turn ends, PermissionRequest, which "runs when Codex is about to ask for approval," and SessionEnd, among others.
As an example, this Stop hook uses macOS osascript to send a desktop alert when every turn finishes. Setting async to true lets Codex continue while the hook runs:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Turn finished\" with title \"Codex\"'",
"async": true,
"timeout": 10
}
]
}
]
}
}
Save it as ~/.codex/hooks.json. A few rules from the docs keep this safe:
- Print nothing, or valid JSON.
Stopexpects JSON on stdout when it exits 0, but "Exit0with no output is treated as success and Codex continues." - Don't decide approvals by accident. For
PermissionRequest, "Plain text onstdoutis ignored," and if no hook returns a decision, "Codex uses the normal approval flow." A hook that only sends an alert leaves the prompt in place. - Trust the hook first. New or changed hooks are skipped until you approve them in
/hooks. - Background limits. Codex runs up to eight background hooks at once per session, and the
Stophook's input includeslast_assistant_messageif you want the text in your alert.
How do notifications work in the desktop app, web and IDE?
ChatGPT desktop app. Per the Notifications page, open Settings "to choose whether turn-completion alerts appear never, only while ChatGPT is in the background, or always. Separate controls let you turn permission and question notifications on or off." Your operating system may ask you to allow notifications. The Activity view, opened from the bell in the sidebar or with Cmd+Option+U on macOS and Ctrl+Alt+U on Windows, lists chats that are unread, running or waiting for you. An optional pet can also show when a chat is Running, Needs input, Ready or Blocked. See the Codex app guide.
Web. Open Settings > Notifications. "Depending on the category and account, channels can include push, email, or SMS." From the task notification settings, Manage tasks opens Scheduled.
IDE extension. The docs say "The IDE extension doesn't provide separate notification controls." Keep the chat open, or configure notify on the connected Codex host. See the Codex IDE extension guide.
Why are Codex notifications not showing?
Work through these in order:
- You are looking at the terminal. With the default
notification_condition = "unfocused", nothing fires while the terminal has focus. Setalwaysto test. - Your terminal ignores OSC 9. In
automode Codex falls back to BEL only when it thinks OSC 9 is unsupported. Setnotification_method = "bel"to rule this out. notifyis in the wrong file. Move it from.codex/config.tomlin the project to~/.codex/config.toml, above the first table header.- The script fails silently. Run it by hand with a sample payload, such as
~/.codex/notify.sh '{"type":"agent-turn-complete","last-assistant-message":"test"}', and check it is executable. - The hook isn't trusted. Open
/hooksand review it. Codex records trust against a hash, so every edit needs a fresh review. - The OS blocks alerts. Check your system notification settings for your terminal app or the ChatGPT desktop app.
For more on config files and their precedence, see the Codex config guide. If you also use Claude Code, the Claude Code notifications guide covers its equivalent setup.
Keep your Codex setup portable
Notification scripts live on each machine, but the prompts and skills you hand to Codex can travel with you. Kipt keeps prompts and Agent Skills as Markdown in a private GitHub repo you own and installs every skill into Claude Code or Codex with one npx skills add command. The free SKILL.md generator turns a prompt you keep reusing into a skill.