Skip to content

Background agent's row ends when the agent list says waiting #246

Closed

Description

@a1exk-dev

What happens

A background general-purpose agent starts its own background shell (sleep 25; echo shell-done) and ends its turn to wait for it. About 6 s in, its Agents & shells row turns ✗ general-purpose · bg waiter · …, with waiting as the reason that the row cut. endTask also queues a ✗ general-purpose waiting toast. All this happens while the shell keeps running under it. 8 s later the agent row leaves, and the shell row moves up to the top level as ◐ $ sleep 25; …. When the shell ends, the agent runs again and finishes, but its row never comes back and no done toast comes. Live on 2.1.292 at release/0.5.0 and at v0.4.0. The live-check row "Ask Claude to start a general-purpose agent that itself runs sleep 30 in the background" in docs/testing/live-checks.md expects the agent row to stay ◐ with the shell nested under it.

Why

A tagged probe logged what $.agent.list() gave for that agent: running → waiting (as the agent's turn ended with its shell live) → running (when the shell's notification woke it) → completed. The vendored AgentStatus type already lists 'pending' | 'running' | 'waiting' | 'idle' | 'completed' | 'failed' | 'killed' at v0.4.0, and says waiting means held on background work the agent owns, and that only completed, failed and killed are ended.

applyAgentList in ctui/hooks/tasks.ts treats every word except running as an end. On waiting it calls endTask with status waiting and a toast, so the row draws ✗ with waiting as its reason. dropEnded then deletes the row 8 s later. The later running and completed find no held task (held?.kind !== 'agent'), so nothing restarts the row or raises the done toast. The shell row's parent no longer exists, so it draws at the top level.

The agent's first <task-notification> also arrives at the waiting point, with <status>completed</status> and a note that the result may be interim. applyNotification already ignores an agent's non-failed notice, so that notice plays no part in the bug.

Ask

In applyAgentList, end a held agent only on completed, failed or killed. Treat pending, waiting, idle and any other word as live: the row stays ◐ with no toast, and an ended row that reads one of them runs again, as running does today. Keep the rest of the change-only logic as it is.

Update MEMORY.md's "Task ends come from notifications; running tasks carry across /clear and /resume" to say that, from 2.1.292, a background agent reads waiting in $.agent.list() while it waits on its own background work and then reads running again. Also say that only completed, failed and killed end a row.

Test seam: ctui/tests/tasks.test.ts for applyAgentList: a running agent whose list goes waiting stays running with no toast, and the list then going running and completed gives one done toast. In ctui/tests/agents-sidebar.test.tsx, add a scenario: $.agent.spawn in the background, a background Bash tool.call with that agentId, and the world's list set to waiting. Assert the agent row stays ◐ with the shell nested under it as └, with no toast. Then set the list to running and then completed, and assert ✓ and a done toast.

Ship it from bugfix/agent-waiting-row, cut from release/0.5.0, with its pull request into release/0.5.0.

Activity

  1. a1exk-dev commented on Oct 10, 2026

    @a1exk-dev
    OwnerAuthor

    Fixed in #254, merged into release/0.5.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions