Opening a completed background session from FleetView hangs forever on "Session is starting"; the wait screen ignores Kitty keyboard input, leaving no way to detach
Summary
Opening a completed background session from the claude agents fleet view hangs forever on Session is starting - showing its transcript until it appears. Ctrl+Z to detach. The session finished normally minutes earlier, so no worker can ever be created for it, and the daemon just re-settles it as done on every attempt.
Two defects stack, and their combination is what makes this bad:
- FleetView attaches to a session that has already finished, then waits indefinitely for a PTY that will never exist.
- That wait screen does not decode the Kitty keyboard protocol, so every keypress is echoed to the screen as raw text instead of being acted on. The on-screen hint
Ctrl+Z to detachis therefore untrue: Ctrl+Z, Ctrl+C and Esc are all inert. There is no keyboard way out of the state at all - the only escapes are closing the terminal tab orkilling the process from another one.
Note that the daemon is healthy throughout. Nothing crashed, nothing was killed. This is purely a client-side attach path that does not check whether the target session is still alive.
Environment
- Claude Code 2.1.224
- macOS 26.6 (build 25G72), arm64 (Apple Silicon)
- Ghostty 1.3.1, which advertises and uses the Kitty keyboard protocol
- Background/daemon mode
Steps to reproduce
- Start a background session and let it run to completion (
state: "done"). - Wait long enough that its worker is gone. In my case the session settled at 16:45:20Z and I opened it at 17:00:42Z, 15 minutes later.
- Run
claude agents, select the completed session in the Completed list, press Enter. - The transcript renders correctly, then the status bar shows
Session is starting - showing its transcript until it appears. Ctrl+Z to detachand never progresses. - Press Ctrl+Z, Ctrl+C, Esc: nothing happens, and the raw escape sequences for those keys are printed into the view.
Evidence
The daemon loops, and never spawns a worker
From ~/.claude/daemon.log (times are UTC; the session is 6941a5b2):
[2026-08-07T16:45:20.929Z] [bg] bg settled 6941a5b2 (done)
[2026-08-07T17:00:42.348Z] [bg] bg claimed-spare 6941a5b2 (fleet)
[2026-08-07T17:01:17.650Z] [bg] bg settled 6941a5b2 (done)
[2026-08-07T17:01:20.205Z] [bg] bg claimed-spare 6941a5b2 (fleet)
[2026-08-07T17:02:01.168Z] [bg] bg settled 6941a5b2 (done)
Each claimed-spare ... (fleet) is one attempt to open the session from the fleet view. Each one settles straight back to done seconds later without a worker ever being born. The client keeps waiting anyway.
The daemon itself is fine: its uptime covers the whole window, and the last shutting down entry predates it by more than two hours. No cause=upgrade, no ENOENT, nothing killed it.
No PTY exists
$ ls -la /tmp/cc-daemon-501/<daemon-id>/pty/
total 0
drwx------@ 2 user wheel 64 Aug 7 16:54 .
drwx------@ 6 user wheel 192 Aug 7 16:36 ..
Empty, and last modified before the first attach attempt. There is nothing to attach to, and this is knowable up front.
The session is listed without a pid, so it is selectable
claude agents --json --all (trimmed):
{
"id": "6941a5b2",
"kind": "background",
"sessionId": "6941a5b2-a20c-40fb-ba90-403728e175bf",
"name": "...",
"state": "done"
}
Compare with a live entry, which carries both pid and status:
{
"pid": 85066,
"id": "ee4076db",
"kind": "background",
"name": "...",
"status": "busy",
"state": "working"
}
The completed session has neither pid nor status, yet it is offered as an openable row.
The keyboard input echoed as text
The characters flooding the view decode cleanly as Kitty keyboard protocol sequences (CSI unicode-key-code ; modifiers u, modifiers being 1 + bitmask, so Ctrl alone is 1 + 4 = 5):
| Printed | Key |
|---|---|
| ^[[99;5u | Ctrl+C (99 = c) |
| ^[[27u | Esc |
| ^[[127;5u | Ctrl+Backspace |
| ^[[I | focus-in event (DECSET 1004) |
So the protocol is enabled on the terminal, but this particular screen consumes none of it. Every key the hint tells the user to press is dropped and echoed.
Expected
- Selecting a completed session should open its transcript in a read-only view, or state plainly that the session has ended, rather than attempting an attach that cannot succeed. The absence of a PTY and of a
pidis known before the attempt. - If the wait state is kept, it must time out instead of waiting forever, and it must honour the keys it advertises. A screen that prints
Ctrl+Z to detachwhile discarding Ctrl+Z traps the user with no keyboard exit.
Impact
The user has to close the terminal tab or kill the process from elsewhere. Because the TUI is killed rather than exited, it never restores the terminal mode, so the shell is left in raw mode and needs a blind reset.
This also compounds an existing report: #77683 notes that completed background sessions cannot be removed from the fleet view and persist as status: null. They stay listed, so they stay selectable, so this trap stays reachable.
Separately, the Session is starting message is emitted whenever no PTY is available, regardless of why. I have hit it before for genuinely broken reasons (#84827, a daemon killed mid-upgrade). Having the identical message cover both a dead daemon and a perfectly normal completed session makes it useless as a diagnostic and sent me down the wrong path twice.