Codeman logocodeman GitHub →

Get notified when Claude Code finishes or needs your input

Updated 2026-09-25

On this pageWhat happens by defaultA desktop notification from a hookWhen each notification firesThe Stop hook: the moment a turn endsPush to your phoneHow Codeman handles it

Claude Code already fires a notification when it finishes or pauses for a permission prompt and you appear to be away. It shows up as a desktop notification only in Ghostty, Kitty and iTerm2 by default. Anywhere else, set preferredNotifChannel to terminal_bell, or add a Notification hook that runs any command you like, including a push to your phone.

What happens by default

From Anthropic's terminal configuration docs:

The simplest fix for other terminals is the bell, in ~/.claude/settings.json:

{
  "preferredNotifChannel": "terminal_bell"
}

A desktop notification from a hook

Hooks are commands Claude Code runs at points in its lifecycle. A Notification hook runs whenever Claude Code sends a notification, whatever your notification channel is set to. On Linux:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          { "type": "command", "command": "notify-send 'Claude Code' 'Claude Code needs your attention'" }
        ]
      }
    ]
  }
}

On macOS, replace the command with osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'. If nothing appears, macOS may not have given Script Editor notification permission; run that command once in Terminal, then allow Script Editor under System Settings > Notifications. notify-send needs a notification daemon, which SSH sessions and containers usually lack. Type /hooks in Claude Code to check what is loaded (the menu is read-only).

When each notification fires

An empty matcher fires on every notification type. To narrow it, list types separated by |:

Matcher Fires when
permission_prompt Claude needs you to approve a tool use and you have not typed for about six seconds
idle_prompt Claude finished responding about 60 seconds ago and you have not typed since
elicitation_dialog An MCP server opened a form and you have not typed for about six seconds
quota_auto_resume_fired Claude Code continued your task after a usage limit reset (v2.1.234 and later)

The idle_prompt delay matters: a session can be finished for a full minute before you hear about it. Full list in the hooks reference.

The Stop hook: the moment a turn ends

A Stop hook runs as soon as the main agent finishes responding. It does not run when you interrupt Claude, and API errors fire StopFailure instead. Its input includes last_assistant_message, the text of Claude's final reply, so a notification can say what happened without parsing the transcript.

Two cautions. Stop fires after every turn, not only when a long task is done, so it is noisy while you are working at the keyboard. And a Stop hook that returns "decision": "block" keeps Claude working; a notification hook should print nothing and exit 0.

If you want to hear about permission prompts instantly rather than after six seconds, the PermissionRequest event runs the moment Claude asks.

Push to your phone

A desktop notification does not help when you are away from the desk. Hooks receive a JSON object on stdin with cwd, and for notifications message, title and notification_type, so one script can forward either event. This one uses ntfy, which needs no account:

#!/usr/bin/env bash
# ~/.claude/hooks/push.sh: forward a Claude Code hook event to your phone via ntfy.
topic='pick-a-long-random-topic-name'      # anyone who knows it can read your pushes
input=$(cat)
project=$(basename "$(jq -r '.cwd // "."' <<<"$input")")
title=$(jq -r '.title // "Claude Code"' <<<"$input")
msg=$(jq -r '.message // .last_assistant_message // "Finished"' <<<"$input" | head -c 300)
curl -s -H "Title: $title ($project)" -d "$msg" "https://ntfy.sh/$topic" >/dev/null
{
  "hooks": {
    "Notification": [
      { "matcher": "permission_prompt|idle_prompt",
        "hooks": [{ "type": "command", "command": "$HOME/.claude/hooks/push.sh" }] }
    ]
  }
}

Make the script executable (chmod +x), install the ntfy app on your phone and subscribe to the same topic. The ntfy docs say it plainly: the topic is essentially a password. Messages pass through the ntfy.sh server, so if Claude's replies might contain anything sensitive, send only the project name or run your own ntfy server. Add the same command under Stop if you want a push after every turn.

How Codeman handles it

Codeman runs Claude Code and other agent CLIs in tmux sessions behind a browser dashboard, and writes Claude Code hooks into each project's .claude/settings.local.json so the CLI reports permission prompts, idle prompts and finished turns back to it. Codeman only updates the hook block it wrote, so your own hooks, like the ones above, keep working next to it.

What you get from those events:

These precise signals exist for Claude Code sessions, and DeepSeek Harness sessions report the same states themselves. Other CLIs have no hooks, so Codeman falls back to watching terminal output, which is coarser. See Notifications And Approvals and Hooks And Integrations.