Completed background-agent sessions can't be deleted from `claude agents` view on WSL2 (worker not reaped; daemon re-dispatches)

Open 💬 1 comment Opened Jul 8, 2026 by er9910

Summary

On WSL2, completed background-agent sessions cannot be deleted from the claude agents fleet view (Ctrl+X on a "Completed" session is a no-op). The delete works fine on native machines. Root cause is not the keybinding — Ctrl+X input reaches the app (it stops a running session correctly). The problem is a background-session lifecycle bug on WSL: a completed session's worker process is never reaped, and killing it causes the supervisor daemon to re-dispatch the session (re-runs the original prompt), so the view's delete has a live/self-resurrecting backend it can never remove.

Environment

  • Claude Code: 2.1.204
  • OS: WSL2 (Ubuntu), Linux 6.6.114.1-microsoft-standard-WSL2
  • Terminal: Windows Terminal
  • Native binary is a proper Linux ELF (installed as bin/claude.exe, but file confirms ELF x86-64)

Steps to reproduce

  1. Dispatch a background session: claude --bg "reply 'done' and exit"
  2. It reaches state done almost immediately (shows in claude agents under Completed).
  3. In the interactive claude agents view, select the completed session and press Ctrl+X to delete → nothing happens (no "ctrl+x again to delete" confirmation, no removal).

Expected

Ctrl+X on a completed session deletes it from the view (as it does on non-WSL machines).

Actual

The completed session stays in the list; Ctrl+X is a no-op on it. (Ctrl+X on a running session works — two presses stop it into "Completed" — so input delivery is fine.)

Root-cause evidence (reproduced)

For a session that is state: done (with firstTerminalAt set):

  • Its worker process (bg-pty-host … --session-id/--resume) stays alive indefinitely after completion (observed alive across repeated checks; never reaped).
  • ~/.claude/daemon/roster.json keeps the worker; claude agents --json --all still lists it as done.
  • Killing the worker PID → the supervisor daemon re-dispatches it, re-launching claude.exe --session-id <uuid> "<original prompt>" (a fresh worker, attempt increments). So the completed session self-resurrects.
  • The transient supervisor daemon (daemon run --origin transient --spawned-by {…"claude agents"…}) frequently outlives its spawner (spawner PID already exited) and keeps resurrecting completed sessions as an orphan.
  • claude stop <id> DOES work: it deregisters the session from the daemon (removed from roster, no re-dispatch). After that, only the leftover done job/transcript records remain and the entry finally clears once those are removed.

This strongly suggests the fleet-view "delete" path relies on the worker terminating / daemon deregistration that never completes on WSL, whereas claude stop's control-protocol path succeeds.

Workaround (for other WSL users)

  • claude stop <id> to deregister + stop re-dispatch, then remove the leftover ~/.claude/jobs/<id>/ and ~/.claude/projects/<proj>/<uuid>.jsonl records so it leaves the view.

Ask

  • On WSL2, reap completed background workers, and make the fleet-view Ctrl+X "delete" use the same control path as claude stop so it actually removes completed sessions.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗