FleetView Ctrl+X delete leaves orphaned roster.workers entry + live worker process (row stuck as "Completed"); `claude rm` cleans it fully [v2.1.204]

Open 💬 0 comments Opened Jul 8, 2026 by talmes1502

Summary

In the agent view (claude agents / FleetView), pressing Ctrl+X twice to delete a session whose worker process is still alive does an incomplete teardown: it removes ~/.claude/jobs/<id>/state.json but leaves the ~/.claude/daemon/roster.jsonworkers[<id>] entry and the underlying worker process alive. The row then re-renders permanently as "Completed" and cannot be dismissed with further Ctrl+X. claude rm <id> performs the full teardown and clears it.

This is most reproducible with spare-pool-derived sessions (dispatch.source: "spare"), whose bg-pty-host / bg-spare processes outlive a "stop".

Environment

  • Claude Code v2.1.204
  • macOS (Darwin 24.x), iTerm2 (no ^X key remap; not inside tmux/screen; no ~/.claude/keybindings.json)

Repro

  1. From the agent view, dispatch a new session (it claims a spare worker).
  2. Interact minimally so it reaches an idle/awaiting-input state.
  3. Select its row and press Ctrl+X twice to delete it.

Expected

The row is removed from the view (same as claude rm <id>): worker process terminated, roster entry pruned, jobs/<id>/ and sessions/<pid>.json removed.

Actual

The row flips to "Completed" and stays. Pressing Ctrl+X again is a no-op.

Root cause (on-disk analysis)

The agent view renders a session if it appears in either roster.json.workers[<id>] or has a jobs/<id>/state.json. Comparing the two delete paths on a session with a live worker:

| Record | Ctrl+X-delete | claude rm <id> |
|---|---|---|
| jobs/<id>/state.json | removed | removed |
| roster.jsonworkers[<id>] | left behind | pruned |
| worker process (bg-pty-host / bg-spare) | left alive | killed |
| sessions/<pid>.json | left | removed |

Because the worker process stays alive, the daemon retains its roster.workers entry, so the row keeps rendering. With jobs/<id>/state.json gone there is no "running" state, so it defaults to "Completed". The second Ctrl+X does nothing because the delete handler already ran and there is no state.json left to act on — it never re-issues the process-kill / roster-prune.

A/B evidence

For an orphaned session left by Ctrl+X (worker PIDs alive, roster.workers[<id>] present, no jobs/<id>/state.json), running claude rm <id> results in:

  • roster.workers no longer contains <id>
  • the bg-pty-host / bg-spare PIDs are terminated
  • jobs/<id>/ and sessions/<pid>.json removed
  • claude agents --json --all no longer lists it

So the only functional difference is that claude rm instructs the daemon to terminate the worker and prune the roster entry, which the Ctrl+X-delete handler omits.

Suggested fix

Make the agent-view Ctrl+X-delete action invoke the same full teardown as claude rm: terminate the worker process and prune roster.workers[<id>] (in addition to removing jobs/<id>/state.json), especially for dispatch.source: "spare" sessions whose PTY-host processes survive a stop.

Workaround

Use claude rm <id> instead of Ctrl+X for such sessions.

View original on GitHub ↗