The short answer
  • Claude Code: a Notification hook in settings.json runs any command when Claude needs you, for example an osascript call on macOS. Setting preferredNotifChannel to terminal_bell is the zero-script option.
  • Codex CLI: notify in config.toml runs an external program when a turn completes. The [tui] section controls built-in terminal notifications.
  • Limit: all of these say that something happened. With several sessions in tmux panes, tabs or worktrees, they do not say which session it was.
  • Beyond that: people build a small dashboard, use a session manager, or route alerts to chat. MAICA, our own tool, is a fourth option and is in private beta.

1. Claude Code: hooks, bell and desktop notifications

Claude Code raises a notification event when it finishes a task or pauses for a permission prompt and you appear to be away from the terminal. Two details from the documentation matter in practice. A permission_prompt notification fires after the prompt has waited about six seconds. An idle_prompt notification fires when Claude finished responding about 60 seconds ago and you have not typed since.

What happens with that event depends on your terminal. By default Claude Code sends a desktop notification only in Ghostty, Kitty and iTerm2. In other terminals you set preferredNotifChannel to "terminal_bell" in ~/.claude/settings.json to ring the bell, or you attach a hook.

A Notification hook is a command that Claude Code runs when the event fires. This is the macOS example from the Claude Code hooks guide:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

The hook runs alongside the built-in notification and cannot block anything; its exit code and stderr are ignored. It receives JSON on stdin with session_id, cwd, notification_type and message. You can narrow it with a matcher such as permission_prompt|idle_prompt. The Stop hook is a separate event that runs when Claude finishes responding.

Running inside tmux? Desktop notifications and progress updates do not reach the outer terminal by default. The terminal configuration page lists set -g allow-passthrough on for ~/.tmux.conf as the fix.

2. Codex CLI: notify and TUI notifications

Codex has two separate mechanisms, both configured in config.toml. notify runs an external program for supported events. The documentation lists agent-turn-complete and says the program receives a JSON argument with fields such as type, thread-id, turn-id, cwd, input-messages and last-assistant-message. That makes it a fit for webhooks and desktop notifiers.

The [tui] section controls notifications built into the terminal interface: whether they are on, which escape sequence is used (auto, osc9 or bel), and whether they fire only when the terminal is unfocused or always.

notify = ["python3", "/path/to/notify.py"]

[tui]
notifications = true
notification_method = "auto"      # auto, osc9 or bel
notification_condition = "unfocused"  # unfocused or always

Check the current Codex documentation before copying this, since the configuration surface changes between versions.

3. OS level: macOS notifications from a hook

Because a hook is just a command, anything your operating system offers can be the notification. On macOS the standard route is osascript with display notification, as in the example above. The hooks guide has one gotcha: osascript routes notifications through Script Editor, and if Script Editor has no notification permission the command fails silently. Run osascript -e 'display notification "test"' once, then allow notifications for Script Editor in System Settings. Command-line tools such as terminal-notifier are a common alternative, and the same pattern works on Linux and Windows with their own commands.

Because the payload carries cwd, a small wrapper script can put the project directory into the notification text. That already helps with the next problem, but only partly.

4. Where this stops working

All of the above answers one question: did something happen? That is enough for one session. It stops being enough when you run several at once, in tmux panes, terminal tabs or git worktrees.

  • A sound has no address. A bell or a banner says that some session needs you. You still open the panes one by one to find it.
  • Context has to be rebuilt. When you reach the right session, you first reconstruct what it was doing and why it stopped.
  • Notifications pile up. Three agents asking within a minute produce three banners with the same text and no ranking.
  • There is no overview. Nothing shows which sessions are working, which are blocked and which finished ten minutes ago.

None of this is a flaw in the notification features. They were built to tell one person that one agent is waiting. Running many agents in parallel is a different job: deciding where your attention goes next.

5. What people use instead

Three patterns come up repeatedly.

  • A small dashboard. Hooks write events to a file or a local server, and a page or terminal view shows one row per session. It is cheap to start and you own it. The cost is that you also maintain it, and jumping back to the right terminal is usually the missing piece.
  • Session managers. Tools that start, name and list your agent sessions, often on top of tmux or worktrees. They help with organization. Whether they tell you who is waiting depends on the tool.
  • Chat pushes. A hook or Codex notify program posts to Slack or Telegram. This reaches you away from the desk, which the others do not, but a message in a channel still does not take you back to the right terminal.

Which one fits depends on how many sessions you run and whether you work at one desk or move around. Up to two or three sessions, hooks plus a project name in the message are usually enough.

6. Where MAICA fits

MAICA is our own tool, so weigh this section accordingly. It is built for exactly the gap above: running Claude Code and Codex in parallel without constantly checking terminals. MAICA observes your sessions locally in the background and, when a permission request, a decision, a failure or a finished review needs a human, it ranks that in an attention queue, shows which workstream it is, and brings you back toward the right terminal session.

What it is not: a coding agent, and not an orchestrator that starts or schedules your agents. You keep launching Claude Code and Codex the way you do now. It works with sessions in separate terminals, tmux panes or git worktrees, and it is local-first: source code, prompts, conversations and diffs stay on your machine.

Where it stands: private beta, macOS first, with Linux support being validated, for Claude Code and Codex. Productivity measurement is under development and not part of the current beta promise. If you already run several agent sessions and lose time finding the one that needs you, you can request private beta access.