DEV Community

Little Pan
Little Pan

Posted on Originally published at ponymux.com

How to know which Claude Code or Codex agent needs you

You start three agents and go read something. Twenty minutes later one of them has been waiting ten minutes for approval to run npm install. Another finished long ago. The third is still working. You find out by clicking through every tab.

Both agents can tell you when they need you. The defaults just need a little help:

  • Claude Code: notifications come from your terminal. Pick the channel in /config, or add a Notification hook.
  • Codex: desktop notifications are on by default, but only while the terminal isn't in front. Tune them under [tui] in ~/.codex/config.toml.
  • Name the project: a short hook script puts the folder name in the notification title, so you know which agent it is.
  • The catch: a notification tells you something happened. It doesn't take you back to the right tab.

When do Claude Code and Codex notify you?

Claude Code sends a notification when it needs permission to use a tool, and when it has finished and you've been idle for a minute. It sends it through your terminal. In iTerm2, Ghostty, and kitty that's a desktop notification. In Apple Terminal it's the bell. Change the channel with /config inside a session. The Notifications setting offers the terminal-specific options, the bell, or off.

Codex sends a desktop notification when a turn finishes and when it asks for approval to run a command or edit files. By default it only does this while the terminal is in the background, which is usually what you want. The settings live in ~/.codex/config.toml:

[tui]
notifications = true                 # or a list, such as ["approval-requested"]
notification_condition = "unfocused" # "always" to notify even when the terminal is in front
Enter fullscreen mode Exit fullscreen mode

Both work well with one agent. With four, "Claude Code needs your permission" doesn't say which of the four.

How do I see which project a notification is about?

Use a hook. Both agents can run a command on these events and pass it a JSON description that includes the working directory. This script turns that into a notification titled with the agent and folder name:

#!/bin/sh
# ~/bin/agent-notify.sh — usage: agent-notify.sh "Claude Code"
jq -r --arg agent "$1" '
  (.message // (if .hook_event_name == "PermissionRequest" then "Needs your approval" else "Finished its turn" end)) as $body
  | "display notification \($body | @json) with title \("\($agent) · \(.cwd | split("/") | last)" | @json)"
' | osascript >/dev/null
Enter fullscreen mode Exit fullscreen mode

Save it and run chmod +x ~/bin/agent-notify.sh. It needs jq, which ships with macOS 15 and later.

For Claude Code, add a Notification hook to ~/.claude/settings.json:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt|idle_prompt",
        "hooks": [{ "type": "command", "command": "~/bin/agent-notify.sh 'Claude Code'" }]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

For Codex, add Stop and PermissionRequest hooks to ~/.codex/hooks.json:

{
  "hooks": {
    "Stop": [{ "hooks": [{ "type": "command", "command": "~/bin/agent-notify.sh Codex" }] }],
    "PermissionRequest": [{ "hooks": [{ "type": "command", "command": "~/bin/agent-notify.sh Codex" }] }]
  }
}
Enter fullscreen mode Exit fullscreen mode

Codex asks you to review new hooks the next time it starts, and /hooks inside a session shows what's installed. The script prints nothing, so it doesn't change whether a permission request is approved. Now a notification reads "Claude Code · api: Claude needs your permission to use Bash", and you know where to go. If you now get two notifications for the same event, turn the built-in one off: Notifications in Claude Code's /config, or notifications = false under [tui] for Codex.

Why does a notification still leave me hunting for the tab?

Because it comes from the agent, not from the window it runs in. Clicking a display notification banner opens Script Editor. Clicking the terminal's own notification brings the terminal forward, but not necessarily the right tab. With several agents per window, you still scan tabs for the one with the prompt.

A hook can't fix this, and neither can the terminal settings. What's missing is a place that tracks each agent's state next to the terminal it runs in.

Can I see every agent's status at a glance?

That's what PonyMux does. Each Terminal running Claude Code or Codex shows the agent's state on its row in the Terminal list:

  • Waiting for you: approval or an answer is needed.
  • Running: the agent is working.
  • Unread: it finished something you haven't looked at yet.
  • Standing by: ready for the next prompt.
  • Will come back: the agent is idle, but background work or a subagent it started is still running.
  • Error: it stopped because something went wrong.

Agent status on each Terminal row: running, waiting for you, standing by, unread, and will come back.
Agent status on each Terminal row: running, waiting for you, standing by, unread, and will come back.

When any Terminal in the list has a status, a badge at the bottom of the list shows the count. Click it to jump to the next one, and click again to cycle through the rest. The list order doesn't change.

To see only the agents, select Agents in the sidebar. It lists every Terminal where Claude Code or Codex is running right now, plus the ones whose agent was still active when you last quit PonyMux, so four agents spread across different projects and Lists show up in one place. Running agents come first, then the ones left from your last quit, each group in your usual Terminal order. It isn't a folder you manage: Terminals join and leave it as their agents start and stop.

The Agents collection in the sidebar lists the Terminals running Claude Code or Codex, across every project and List.
The Agents collection in the sidebar lists the Terminals running Claude Code or Codex, across every project and List.

PonyMux also sends its own notifications for finished turns, permission requests, input requests, and errors, and you can set each kind to Off, Silent, or Sound in Settings → General. Clicking a notification opens PonyMux on the Terminal it's about, which is the step a hook can't do. Agent status needs the Claude Code or Codex integration, which you connect once from the bottom of the sidebar.

For every status and notification setting, see Agent Status and Notifications.


Originally published on ponymux.com, where the demos are interactive.

Top comments (0)