Codex notifications on Mac know when Codex CLI needs you

Codex CLI pauses when it needs an approval and when it finishes a turn. Here is how to find out on a Mac without watching the terminal, from the settings it already has to a banner for every approval.

Updated · Cadence Labs

Short answer

Codex CLI already notifies you. Its [tui] notifications setting is on by default and fires when a turn finishes (agent-turn-complete) or Codex asks for approval (approval-requested), but only while the terminal is not focused. In iTerm2 or Ghostty that shows up as a macOS notification; in Terminal.app it is a bell.

For a real macOS banner in any terminal, point the notify setting in ~/.codex/config.toml at a small script (it runs when a turn finishes), and add a PermissionRequest hook for approvals. Both setups are below. If you run several agents, Cadence shows every one on a toolbar and lets you answer Codex from one Inbox.

When Codex waits for you

Codex CLI stops and waits in two situations:

Nothing happens until you answer. An agent that stopped on an approval a minute into a long task is still waiting an hour later.

Option 1: Codex's built-in notifications

Codex's terminal interface has notifications built in. They are on by default, so you may only need to check how your terminal shows them. These are the settings, with their defaults:

# ~/.codex/config.toml
[tui]
notifications = true                 # or a list: ["agent-turn-complete", "approval-requested"]
notification_method = "auto"         # auto | osc9 | bel
notification_condition = "unfocused" # unfocused | always

In Terminal.app you get the bell. Terminal can play a sound, or badge and bounce the Dock icon, when a bell rings in a background tab; look in its profile settings under Advanced. In tmux, set -g monitor-bell on marks the window that rang.

Option 2: a notify script for a macOS banner

The notify setting runs a program of your choice when Codex emits an event. Today the only event is agent-turn-complete, so this covers "Codex is done", not approvals. Codex passes the event as a single JSON argument with fields such as type, cwd, input-messages and last-assistant-message.

Step 1: write the script

Save this as ~/.codex/notify.sh. It posts a notification titled with the project folder and Codex's last message. It uses jq (brew install jq).

#!/bin/sh
# Codex passes the event as one JSON argument.
[ "$(printf '%s' "$1" | jq -r '.type')" = "agent-turn-complete" ] || exit 0
msg=$(printf '%s' "$1" | jq -r '(."last-assistant-message" // "Turn complete")[0:200]')
dir=$(basename "$(printf '%s' "$1" | jq -r '.cwd // "."')")
osascript -e 'on run argv' \
  -e 'display notification (item 1 of argv) with title (item 2 of argv) sound name "Glass"' \
  -e 'end run' "$msg" "Codex: $dir"

Make it executable with chmod +x ~/.codex/notify.sh. Passing the text to osascript as arguments keeps quotes in Codex's message from breaking the command.

Step 2: point Codex at it

Add this line to ~/.codex/config.toml, using the full path to your home folder:

notify = ["/Users/you/.codex/notify.sh"]

notify is a top-level key, so put it above the first [section] header in the file. A line placed under [tui] belongs to [tui] and does nothing.

Step 3: test it

Start a new Codex session, ask for something small, and switch to another app. When the turn ends, a banner should appear. If it does not, open System Settings → Notifications: notifications from osascript are listed under Script Editor, and a Focus mode can hide them.

Option 3: a hook for approval requests

Codex also has hooks: commands it runs at fixed points, configured in ~/.codex/hooks.json or inline in config.toml. They are on by default. The PermissionRequest hook runs when Codex is about to ask for approval, which is the event notify does not cover.

Save this as ~/.codex/hooks/approval.sh. It reads the request from standard input and posts a banner. It prints nothing, so Codex goes on to show its normal approval prompt.

#!/bin/sh
# Codex sends the approval request as JSON on standard input.
input=$(cat)
what=$(printf '%s' "$input" | jq -r \
  '(.tool_input.description // .tool_input.command // .tool_name // "Approval needed") | tostring | .[0:200]')
dir=$(basename "$(printf '%s' "$input" | jq -r '.cwd // "."')")
osascript -e 'on run argv' \
  -e 'display notification (item 1 of argv) with title (item 2 of argv) sound name "Glass"' \
  -e 'end run' "$what" "Codex needs approval: $dir" >/dev/null

Then register it in ~/.codex/hooks.json:

{
  "hooks": {
    "PermissionRequest": [
      {
        "hooks": [
          { "type": "command", "command": "/bin/sh ~/.codex/hooks/approval.sh" }
        ]
      }
    ]
  }
}

Codex runs a new or changed hook only after you review and trust it. Start Codex, type /hooks, and trust the hook. A hook that prints an allow or deny decision would answer the request itself; this one only notifies, so you still decide.

Where notifications fall short

Banners are enough for one or two sessions. With more, the same gaps show up as with any agent:

Option 4: Cadence's toolbar and Inbox

Cadence is a free macOS app that watches your coding agents and collects what they need from you. It runs Codex in herdr, a terminal runtime that knows when an agent is working, waiting or done, so you need no notify script and no terminal setting.

Set it up

  1. Download Cadence. Install codex and sign in once in a normal terminal; Cadence starts it under your own OpenAI sign-in.
  2. Open ⋯ → New agent… on the toolbar and pick Codex. If herdr is missing, the view shows the install command; run it and click I installed it.
  3. Enter the Folder and an optional First message, then start it. Or double-tap ⌥ and say "start a Codex agent in the api folder".

Since 0.5.6 you can also keep typing codex in your own terminal. Turn on Settings → Agents → Your own terminals, and codex started in Ghostty, iTerm, Terminal or your editor runs through Cadence. The terminal looks and works the same. It adds one line to ~/.zshrc, and you can turn it off any time.

See state at a glance

The toolbar on the edge of your screen has one dot per agent: blue working, amber needs you, green done. Codex sits next to Claude Code and any other CLI you run, each with a short title written from what it is doing.

Answer without switching windows

When Codex asks for approval or prints numbered options, the question lands in the Inbox. Press 1 to 9 to answer, Space to type, or V to speak, and Cadence types your answer into Codex's terminal. Esc takes it back within two seconds. Finished turns arrive as cards with a short recap.

Sound, banners and your phone

In Settings → Agents, Text-to-speech reads completions and approval requests aloud, and Notifications turns macOS banners for agent events on or off. The iPhone app, in a private TestFlight beta, shows the same cards and puts an agent's options on its notifications as buttons.

Common questions

Why do I get no Codex notification in Terminal.app?

Terminal.app does not show OSC 9 notifications, so Codex falls back to the bell, and by default only when the window is not focused. Turn on the bell's visual or Dock options in Terminal's profile settings, or use the notify script above for a real banner.

Does the Codex notify setting fire for approval requests?

No. notify currently runs only for agent-turn-complete. For approvals, use the built-in approval-requested notification in [tui] notifications, or a PermissionRequest hook as shown above.

Why does my Codex hook not run?

Codex skips new or changed hooks until you trust them. Run /hooks in Codex and trust it. Also check that hooks are not turned off with hooks = false under [features], and that the script works when you pipe a sample JSON object into it.

Does Cadence change my Codex config?

No. Cadence starts Codex in a herdr terminal and reads its screen to tell when it is waiting. It does not edit ~/.codex/config.toml or hooks.json, and Codex keeps using its own sign-in.