Guide

How to get Codex notifications on macOS

Codex can tell you when a turn finishes or when it is waiting for your approval, and it has two settings of its own for doing that on a Mac. The built-in [tui] notifications go through your terminal, so what you see depends on the terminal. A notify script runs a program of your choosing when a turn completes, and that program can post a real macOS banner from any terminal. This guide covers both, tested, and then where a notch app fits.

Tested on Codex CLI 0.163.0 on macOS, October 2026 · settings from OpenAI's Codex configuration docs

Why you may be getting nothing

Codex does not draw macOS notifications itself. In the terminal UI it writes an escape sequence and leaves the rest to the terminal: either OSC 9, which some terminals turn into a desktop notification, or a plain bell. Terminals such as iTerm2 and Ghostty have a notification path for OSC 9. Apple's Terminal does not, so there the most you get is the bell, and only if the bell is switched on in the profile.

So the same Codex setting looks broken in one terminal and works in another, and a run you walked away from finishes in silence. The first level below fixes the terminals that can show a notification; the second works in all of them.

Level 1: the [tui] notification settings

Three keys in the [tui] table of ~/.codex/config.toml control the terminal UI's own notifications:

# ~/.codex/config.toml [tui] notifications = true notification_method = "auto" # or "osc9", or "bel" notification_condition = "always" # or "unfocused"
  • notifications turns them on. It also takes a list of event types instead of true, such as ["agent-turn-complete", "approval-requested"], to keep only the ones you want.
  • notification_method picks the channel. auto, the default, uses OSC 9 when the terminal appears to support it and falls back to the bell. osc9 and bel force one.
  • notification_condition decides when: unfocused only while the terminal does not have focus, always regardless.

With those settings on Codex 0.163.0, a command that needed approval produced an OSC 9 notification reading Approval requested: followed by the command, and the end of the turn produced one carrying Codex's final message. With notification_method = "bel" inside tmux, the approval rang the bell and tmux flagged that window, which is what you want if you run several sessions in tmux windows.

Whatever the channel, macOS has to be willing to show the banner. Check System Settings, Notifications, and confirm your terminal app may notify and is not silenced by a Focus mode.

Level 2: a notify script that posts a real banner

The root-level notify setting names a program Codex runs when a turn completes. Codex passes it one argument, a JSON object, and the program can do anything with it, including post a macOS notification with osascript, which works whatever terminal Codex is running in.

This is the script used for this guide, unchanged. It reads the event type, the folder the session runs in and Codex's last message, and puts the folder in the banner's title so you can tell sessions apart:

#!/bin/bash # ~/.codex/notify.sh - run chmod +x ~/.codex/notify.sh after saving. # Codex runs this with one JSON argument when a turn completes. payload="$1" field() { /usr/bin/python3 -c 'import json,sys; print(str(json.loads(sys.argv[1]).get(sys.argv[2]) or "")[:200])' "$payload" "$1" } [ "$(field type)" = "agent-turn-complete" ] || exit 0 folder=$(basename "$(field cwd)") message=$(field last-assistant-message) /usr/bin/osascript \ -e 'on run argv' \ -e 'display notification (item 2 of argv) with title (item 1 of argv)' \ -e 'end run' \ "Codex: $folder" "${message:-Turn complete}"

Then point Codex at it. notify is a top-level key, so it goes above the first [table] header in the file, and it takes the command as a list:

# ~/.codex/config.toml - notify above any [table] notify = ["/Users/you/.codex/notify.sh"] [tui] notifications = true

Give the script's full path, as above. The payload the script received on Codex 0.163.0, with the long values shortened:

{ "type": "agent-turn-complete", "thread-id": "01a15188-...", "turn-id": "01a15188-...", "cwd": "/Users/you/projects/api", "client": "codex-tui", "input-messages": ["Create a file named hello.txt ..."], "last-assistant-message": "Created hello.txt containing hi." }

It ran for turns in the terminal UI, where client was codex-tui, and for codex exec, where it was codex_exec. The first time it runs, macOS may ask whether to allow its notifications; allow them, or nothing appears and nothing errors.

The limit to know: notify fires for agent-turn-complete only. When Codex stops for an approval the script is not run at all, which is the moment you most wanted to hear about. Use level 1 for approvals. OpenAI's own example script uses terminal-notifier instead of osascript, and its -activate option brings iTerm2 forward when you click the banner; it is a Homebrew install away if you want that.

Codex in the ChatGPT app

The [tui] table configures the terminal UI. When you run Codex inside the ChatGPT desktop app, the thread lives in the app's window instead, and those settings do not reach it. If you rely on the notify script for threads in the app, test it there first: a one-line script that appends "$1" to a file tells you after a single turn.

The thing notifications cannot do

Both levels solve the same half of the problem: knowing. A banner tells you a run has finished or is waiting; you still have to find the window, find the tab, read the command and answer it there. With three or four sessions running, the folder name in the title is the only thing telling you which one it was, and only because the script above puts it there.

That gap is worth naming, because it is where a notification setup quietly stops being enough. Keeping track of several agents at once covers the rest of that problem.

Level 3: show the request, not a notice about it

CrewTower is a native macOS app that takes the other approach. Instead of notifying you that a Codex session is waiting, it puts the session itself in the MacBook notch: what it is doing, how long it has been going, and the command it wants to run. Codex is one of the agents it speaks to natively, in a terminal and in the ChatGPT app.

Where Codex exposes a decision channel, a Codex hook blocks on a local Unix socket while it waits, and CrewTower answers over that same socket, so the terminal never comes forward and nothing is typed into it. Where there is no channel, the fallback is Jump, which focuses the exact window, tab or split pane instead.

Codex runs a hook only after you have reviewed it, so CrewTower's hooks need that review once; Settings > Integrations in CrewTower shows whether Codex has accepted them. Beyond that, hooks are configured on first launch, with no file to edit.

It costs $9.99 once for one Mac and needs macOS 15 or later. Details on the Codex page.

Which one to pick

  • You use iTerm2 or Ghostty and mostly run one session. Level 1 is enough. Turn on [tui] notifications and stop there.
  • You use Apple's Terminal, or want the banner to say something specific. Add the notify script for finished turns, and keep level 1 on for approvals.
  • You run several sessions and the switching is what hurts. A banner will not fix that; something that shows the request and takes the answer will.

Questions

Why does Codex not notify me while I am looking at the terminal?

With notification_condition = "unfocused" Codex notifies only while the terminal does not have focus. Set it to "always" in the [tui] table if you want a notification either way.

Can the notify script tell me when Codex needs approval?

No. Codex currently runs the notify program for one event, agent-turn-complete, and nothing at all is sent when it stops for an approval. The [tui] notifications do cover approvals, as Approval requested followed by the command.

Where does notify go in config.toml?

At the top level, above the first [table] header. Written under [tui], TOML makes it part of that table, Codex starts without complaint, and the root-level notify it looks for is simply not set.

Why do I hear a bell but see no banner?

Because your terminal received a bell rather than OSC 9, or received OSC 9 and does not turn it into a notification. Apple's Terminal is the usual case. Use the notify script for finished turns, which posts the banner itself whatever the terminal.

Does this work for Codex in the ChatGPT app?

The [tui] settings belong to the terminal UI, so they do not apply to the app's own window. Whether the notify program runs for a thread in the app was not part of this test; point notify at a one-line script that appends its argument to a file, run one turn in the app, and look.

Does any of this let me approve without switching windows?

Not on its own. A notification tells you something happened; it does not carry an answer back. To answer in place, something has to be attached to the decision itself, which is what the approvals guide is about.

See the request, not a notice about it

CrewTower shows every Codex session in the notch and lets you answer from there. Explore the interactive demo on our homepage before purchasing a license.

Get CrewTower for Mac

$9.99 once · macOS 15 or later