Skip to content

Write the ask state when Claude is waiting on the user - #42

Open
auroracapital wants to merge 2 commits into
samleeney:mainfrom
auroracapital:ask-state
Open

Write the ask state when Claude is waiting on the user#42
auroracapital wants to merge 2 commits into
samleeney:mainfrom
auroracapital:ask-state

Conversation

@auroracapital

Copy link
Copy Markdown

ask is read in several places but nothing writes it, so a session waiting for the user cannot be told apart from one that has finished.

Two things cause that.

The Notification branch sets done. The comment above it says "Claude is waiting for user input", which is not what done means. Claude Code sends two different notifications on this event:

  • Claude needs your permission to use Bash means the session is blocked on a person.
  • Claude is waiting for your input is the idle reminder that follows a normal finish.

Treating both as a blocker would relight every finished session about a minute after it ended, so this branches on the message. Permission-shaped messages set ask. The idle reminder leaves the existing state alone rather than overwriting it with done.

set_status never considered ask when folding pane states into a session state, and it returned early on the first working pane, so a later pane waiting on the user was never reached. It now scans every pane and ranks ask above working above wait. A session with one pane waiting on a person and five panes busy still needs a person.

The message match is deliberately loose (permission, approve, confirm, needs your) because the notification text is not a stable API. An unmatched message changes nothing, so a wording change upstream degrades to today's behaviour rather than to a false alarm.

Tested by driving the hook with both payloads and checking the resulting state files, and by running a real permission prompt and an idle timeout in tmux.

🤖 Generated with Claude Code

The Notification branch set "done", under a comment saying "waiting for user
input". Those are different things. `ask` is read by status-summary.sh and
collect.sh but nothing ever wrote it, so a session waiting for permission was
indistinguishable from one that had finished.

Two notifications arrive on this event. "Claude needs your permission to use
Bash" means the session is blocked on a person; "Claude is waiting for your
input" is the idle reminder that follows a normal finish. Treating both as a
blocker would relight every finished session about a minute after it ended, so
the branch keys on the message and the idle reminder now leaves the existing
state alone instead of overwriting it with "done".

set_status also never considered `ask` when folding pane states into a session
state, and returned early on the first `working` pane. A later pane waiting on
the user could not be seen. It now scans every pane and ranks ask > working >
wait.
tmux hands out pane ids from one counter shared by the whole server, not one
per session, so a pane's id gets reused by an unrelated pane in an unrelated
session once the original closes. A hook process that outlives its own pane -
a background job with $TMUX_PANE baked into its environment from start-up, or
a slow tool call whose completion races the pane closing - then writes a
stale status onto whatever now holds that id.

Observed 2026-08-15: pane %3 kept receiving "ask" for a pane that had gone
back to a plain shell, recurring every 13-15 minutes, with no Claude process
anywhere in that pane's tree. The existing two-strike expiry in the hookless
detector cleared it within about a minute each time, so it never stuck for
long, but the write itself was still wrong and briefly flagged the wrong pane
on every recurrence.

set_status now confirms #{pane_current_command} is "claude" for $TMUX_PANE
before writing its status and agent files. All four events this hook handles
(PreToolUse, Notification, Stop, UserPromptSubmit) fire from Claude's own
process before it hands control to a tool, so the pane's foreground command is
still "claude" at the moment each one runs; anything else means the id has
moved on. The session-level status is still derived from whatever pane files
legitimately exist, so a skipped write here does not lose the aggregate
state - it just refuses to manufacture a new one for a pane that no longer
means what its id used to.

Tested in isolation: a pane still showing "claude" writes as before, a pane
now showing a plain shell is skipped, and the session-level status derives
correctly in both cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant