BlogWaiting agents and notifications
How do I know which Claude Code session is waiting for my input?
Make every alert say which session it comes from. Claude Code passes each hook a JSON object with the session's cwd, so a PermissionRequest, a PreToolUse hook on AskUserQuestion and a Stop hook can each show a notification naming the folder or worktree. For background sessions, claude agents already groups every session under "Needs input".
Why the default alert isn't enough
When Claude finishes or pauses for a permission prompt and you seem to be away, Claude Code fires a notification event. By default, it shows a desktop notification only in Ghostty, Kitty and iTerm2. With three or four sessions open, a generic "Claude Code needs your attention" tells you something is waiting, not which tab. And the timing is deliberately lazy:
permission_promptfires once the prompt has waited about six seconds without you typing.idle_promptfires about 60 seconds after Claude finishes responding.
If you are typing in another session, you can miss both.
Without Kanbell: hooks that name the session
1. Write a small script
Save this as ~/.claude/hooks/waiting.sh and make it executable (chmod +x). It needs jq.
#!/bin/sh
input=$(cat)
dir=$(basename "$(printf '%s' "$input" | jq -r '.cwd')")
event=$(printf '%s' "$input" | jq -r '.hook_event_name')
case "$event" in
PermissionRequest) msg="needs a permission" ;;
PreToolUse) msg="is asking you a question" ;;
Stop) msg="is done" ;;
*) msg="needs you" ;;
esac
osascript -e "display notification \"$dir $msg\" with title \"Claude Code\""
Every hook receives cwd and hook_event_name on stdin. In a worktree session, cwd is the worktree root, so the notification reads "feature-auth needs a permission".
2. Register three hooks
In ~/.claude/settings.json:
{
"hooks": {
"PermissionRequest": [
{ "hooks": [{ "type": "command", "command": "$HOME/.claude/hooks/waiting.sh" }] }
],
"PreToolUse": [
{
"matcher": "AskUserQuestion",
"hooks": [{ "type": "command", "command": "$HOME/.claude/hooks/waiting.sh" }]
}
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "$HOME/.claude/hooks/waiting.sh" }] }
]
}
}
What each one covers:
PermissionRequestruns the moment Claude Code is about to ask for permission to use a tool. No six-second delay.PreToolUsewith matcherAskUserQuestionruns before Claude shows you a multiple-choice question.Stopruns when the main agent finishes responding. It doesn't run if you interrupted it.
Run /hooks in a session to check they are registered.
3. Grant notification permission
osascript notifications go through Script Editor. If Script Editor has no notification permission, the command fails silently. Run osascript -e 'display notification "test"' once, then enable Script Editor under System Settings > Notifications.
4. For background sessions, use agent view
If you dispatch sessions with claude agents or claude --bg, agent view (a research preview as of October 2026) shows a "Needs input" group: questions, permission decisions, sandbox network prompts and MCP input requests. The terminal tab title shows the count, such as 2 awaiting input · claude agents. From a normal session, the footer shows ← 2 agents while background sessions wait.
5. Optional: status in the tab
If your terminal implements the OSC 7501 Program Status Protocol, Claude Code v2.1.295 or later reports whether each interactive session is working, waiting or done. Nothing to enable in Claude Code. It doesn't work inside tmux or for background sessions.
Limits of this method
- A notification is a moment, not a state. Once you dismiss it, nothing tells you that session is still blocked ten minutes later.
- Finding the tab is still manual. The alert names the folder. You still hunt for the tab.
- Configuration drift. Hooks live in settings files. New machine, new project-level settings, or a teammate's repository: you set them up again.
- Two sources of truth. Background sessions report in agent view, interactive ones through your hooks.
- Claude Code only. Other CLI agents need their own mechanism, if they have one.
With Kanbell
Kanbell is a macOS app (Apple Silicon) that shows, for each agent, whether it is waiting for you.
- For Claude Code, each agent shows working, waiting or done, and whether it waits on a question or a permission.
- The state stays visible: an orange dot in the project window, in the menu bar and in the overview, for as long as the agent waits. A macOS notification goes out too.
- ⌘⇧J jumps to the next agent that is waiting, so you don't hunt for the tab.
- Codex CLI and Gemini CLI also show their state and permission waits. Other CLI agents run in Kanbell's terminals without tracking.
- Subagents appear on the agent map next to the agents, for Claude Code.
The sessions are ordinary terminal sessions you start yourself. Kanbell runs locally, with no account and no Kanbell server.
FAQ
Why does my Notification hook fire late?
By design. permission_prompt fires after the prompt has waited about six seconds without typing, and idle_prompt about 60 seconds after Claude finishes. Use PermissionRequest for an immediate signal.
Which hook fires when Claude asks me a question?
Claude asks multiple-choice questions through the AskUserQuestion tool, so a PreToolUse hook with the matcher AskUserQuestion runs before the question appears.
Can the terminal tab show the state?
Yes, if your terminal implements the OSC 7501 Program Status Protocol. Claude Code v2.1.295 or later reports working, waiting or done to it, except inside tmux and for background sessions.
Do hooks fire for subagents?
Hooks receive agent_id and agent_type when they fire inside a subagent, so your script can tell them apart. Background subagents surface their permission prompts in the main session.