Show blocked agents as needing input, not as running - #748
Open
simonheimlicher wants to merge 1 commit into
Open
Show blocked agents as needing input, not as running#748simonheimlicher wants to merge 1 commit into
simonheimlicher wants to merge 1 commit into
Conversation
A worktree whose agent is awaiting an answer rendered the same indeterminate spinner as one doing work. The spinner says "work in progress, wait for it", while a blocked agent has stopped and is waiting on you — so the one state that needs attention was the one drawn as needing none. Detection was never wrong here: the scraper returns `.blocked` correctly and the Active Agents panel already renders it in red. The distinction was lost one layer down, where `PaneAgentState.isBusy` folds working and blocked into a single bit and `WorktreeTaskStatus` has only `idle` and `running` to carry it, leaving `WorktreeRow` nothing to branch on. Track the blocked slice alongside the busy aggregate and let the sidebar row read it, so a blocked worktree shows a red attention icon instead of the spinner. `taskStatus` is deliberately unchanged: `prowl list` still reports `running`, so the CLI contract holds and `prowl agents` remains the precise source. A worktree's own create/archive/delete spinner still wins, since it describes the row rather than its agents. Tests cover the working → blocked → working cycle (which leaves the busy aggregate untouched, so only the new flag moves), teardown, and panes with a stale raw state but no detected agent.
onevtail
approved these changes
Aug 30, 2026
onevtail
left a comment
Collaborator
There was a problem hiding this comment.
Verified against exact head 623198a40be5241ccf3cf68fd19b3e630631e30f. The change correctly preserves blocked-agent state through sidebar aggregation while keeping the existing CLI behavior, where blocked agents still map to running.
The state-transition, cross-tab aggregation, Observation invalidation, and teardown paths all behave correctly. The targeted tests, additional cross-tab/Observation checks, static checks, Debug build, and visible CI passed. I found no blocking issues.
onevtail - an assistant to @onevcat
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A worktree row whose agent is blocked wears the running spinner. The spinner says wait for it. A blocked agent is waiting for you, so the row reads as the opposite of what it means. The question sits unanswered until you open the pane for another reason.
The row derives its spinner from
taskStatus == .running, which describes the terminal task. A blocked agent's process is alive and its task is running, so nothing in the row consults agent state at all.PaneAgentStategainsisBlocked, the.blockedslice of the existingisBusy. The aggregate travels the same path as the busy one, through tab and worktree state to the row. The row then prefers a redexclamationmark.circle.fillover the spinner. A worktree being created, archived, or deleted keeps its own spinner, which still wins.prowl list'stask.statusis untouched: a blocked agent still counts as running there, andprowl agentsremains the surface that separates blocked from working.Observed on Prowl Debug at
9075f10bwith Claude Code 2.1.235, in three panes at once. The Active Agents panel readBlockedfor each while the matching worktree rows spun, andprowl agents --jsonagreed with the panel:The third row is the negative control. That pane's screen carried
✻ Waiting for 1 background agent to finishwith a live elapsed counter. Its row spun, and the spinner was correct there.Tests cover the transitions the aggregate has to survive. Those are working to blocked, blocked to idle, tab and worktree teardown, and a pane with no detected agent.