Background-agent adoption never succeeds (0 of 7 attempts): live sessions marked Failed, reap and daemon death unlogged

Status Closed — not planned
Reported on v2.1.251
Maintainer reply None cached
Activity 2 comments · opened Sep 3, 2026 · closed Sep 10, 2026
Provenance: investigated and drafted by Claude Code (Opus 5) running on my machine against my own ~/.claude state, then independently re-verified by a second Claude Code agent given only this text and read-only access. That verification pass falsified an earlier version of this report and the analysis below is the corrected one. I have read it in full and I am filing it deliberately. Machine-generated, human-reviewed, human-endorsed.
Redaction: nothing needed redacting — this is daemon-log lines, job-record field values, timings and session UUIDs. No transcript content is reproduced. Everything quoted is verbatim.

What's Wrong?

Three related problems, all in the daemon's handling of workers across a restart:

  1. Adoption never succeeds. Every bg adopt line in my log reports `adopted=0

respawned=0`. Seven attempts, seventeen workers declared dead, zero ever recovered.

  1. Most daemon deaths are unlogged. Ten daemon start lines, three shutting down

lines. Seven daemon deaths leave no record of why.

  1. The reap itself is silent and its timestamp is misnamed. daemon.log contains zero

occurrences of "reap". And reapedMidWorkAt does not record when the reap happened.

The user-visible result: a background session that outlives its daemon comes back as a red
Failed row, with nothing anywhere explaining what happened to it.

Adoption: 0 for 7

[2026-09-02T11:48:04.550Z] [bg] bg adopt: adopted=0 respawned=0 dead=6
[2026-09-02T12:04:31.929Z] [bg] bg adopt: adopted=0 respawned=0 dead=3
[2026-09-02T12:10:43.418Z] [bg] bg adopt: adopted=0 respawned=0 dead=1
[2026-09-02T23:40:38.064Z] [bg] bg adopt: adopted=0 respawned=0 dead=4
[2026-09-03T00:55:49.190Z] [bg] bg adopt: adopted=0 respawned=0 dead=1
[2026-09-03T09:02:15.360Z] [bg] bg adopt: adopted=0 respawned=0 dead=1
[2026-09-03T09:33:58.511Z] [bg] bg adopt: adopted=0 respawned=0 dead=1

Seven attempts across ten boots, seventeen workers, not one adopted or respawned. If
adoption is expected to work at all, it has never worked once on this machine.

reapedMidWorkAt is not the time of the reap

This is worth its own section because it will mislead anyone triaging from job records — it
misled me for several hours.

Each job directory contains a timeline.jsonl. For job 2aef6790, whose
reapedMidWorkAt is 2026-09-02T20:45:21.596Z, that file contains at exactly that
timestamp:

{"at":"2026-09-02T20:45:21.596Z","state":"working","detail":"…"}

reapedMidWorkAt is the job's last working timestamp — "was mid-work as of T" — not
"reaped at T". The three affected jobs were actually written to at:

| job | reapedMidWorkAt | record last written (updatedAt) | daemon uptime at that write |
|---|---|---|---|
| 2aef6790 | 2026-09-02T20:45:21.596Z | 2026-09-02T23:40:37.587Z | 0.126 s (boot 23:40:37.461) |
| 01eb53de | 2026-09-02T23:54:27.230Z | 2026-09-03T00:55:48.857Z | 0.176 s (boot 00:55:48.681) |
| e31e0dfd | 2026-09-03T02:55:53.830Z | 2026-09-03T09:02:14.908Z | 1.793 s (boot 09:02:13.115) |

All three records were last touched within two seconds of a daemon boot, each immediately
before that boot's bg adopt line. This is the declared-dead-on-restart path, and the field
name actively hides that.

Exhibit: a healthy, resumable session presented as Failed

Job 2aef6790. Its transcript is complete and it resumes cleanly today. Its final records:

20:45:20.359Z  assistant  final content of the turn
20:45:21.603Z  system     subtype: "turn_duration"
20:48:24.642Z  system     subtype: "away_summary"

The away_summary at 20:48 contains real generated prose, so the worker was alive and
running inference three minutes after finishing its turn. The session was idle, waiting on
my input, with an unanswered question in its last message and three open PRs recorded in its
children field.

Its job record was last written at 23:40:37.587Z — 126 ms into a fresh daemon — and it has
shown as red Failed ever since. Nothing failed. I nearly deleted it as dead.

This is NOT the idle-exit

I want to rule this out explicitly, because claude daemon --help documents the on-demand
daemon as intentional and I do not want that used to close a different bug.

Both logged idle exits report live_workers=0:

[2026-09-02T12:25:48.415Z] [supervisor] shutting down (cause=idle_exit, uptime=905s, leases=0, live_workers=0)
[2026-09-03T01:56:53.856Z] [supervisor] shutting down (cause=idle_exit, uptime=3665s, leases=0, live_workers=0)
[2026-09-03T09:24:19.779Z] [supervisor] shutting down (cause=shutdown_op, uptime=1327s, leases=0, live_workers=1)

The idle exit has never terminated a live worker in this log, and the one shutdown that did
have a live worker was my own explicit claude daemon stop. The idle-exit policy is working
as documented. The problem is the seven unlogged daemon deaths and the adoption that
never recovers from them.

What Should Happen?

  • Adoption should reattach to workers that are still alive, or explain in the log why it

cannot. adopted=0 seven times out of seven is either a bug or a feature that does not
exist.

  • The daemon should log why it is going away. Seven of ten exits are currently silent.
  • The reap should log something. daemon.log has zero "reap" lines, so the single most

important state transition for the user is invisible.

  • reapedMidWorkAt should either mean what it says or be renamed, and a separate field

should record when the job was actually marked failed.

  • Failed in the UI should distinguish "the task failed" from "the runtime lost track of

this". Today they are the same red badge, and in my case the second was indistinguishable
from the first for a session that was entirely healthy.

Confident vs. speculation

Confident — checkable in the artifacts above:

  • 10 daemon start, 7 bg adopt (all adopted=0 respawned=0, 17 workers), 3 `shutting

down, 0 occurrences of "reap" in daemon.log`.

  • reapedMidWorkAt equals a state:"working" entry in the job's own timeline.jsonl.
  • All three affected job records were last written within 2 s of a daemon boot.
  • 2aef6790 was alive and running inference at 20:48:24.642Z; its record was last written

at 23:40:37.587Z; it is resumable today and displays as Failed.

  • Both logged idle exits had live_workers=0.

Speculation — offered as leads, not claims:

  • I cannot prove 2aef6790's worker was still alive at 23:40; only that it was alive at

20:48 and that the daemon hosting it died unlogged somewhere in between. If it was
alive, this is "adopt cannot reattach to a live worker". If it was not, this is "adopt
cannot distinguish a crashed worker from a resumable session, and reports it as failure".
Both are worth fixing; I cannot tell you which one you have.

  • All three affected jobs are template: "bg" with interactiveLineage: true. Three of the

six jobs of that shape were hit and none of the other six. With n=3 and no control for
which jobs happened to be alive when a daemon died, I do not think this is a real signal —
I mention it only so you can rule it out rather than rediscover it.

Steps to Reproduce

I do not have a deterministic repro. What I can offer instead:

  1. Run background agents through claude agents across several daemon restarts.
  2. grep 'bg adopt' ~/.claude/daemon.log — check whether adopted= is ever non-zero.
  3. Compare daemon start count against shutting down count to see the unlogged exits.
  4. For any job showing Failed, compare state.json's updatedAt against the nearest

daemon start line, and read the job's timeline.jsonl to see what state it was really
in.

If adopted=0 is universal rather than specific to my machine, that alone is reproducible
by inspection and does not need my session history at all.

Notes for triage

Two of the three job records discussed no longer exist in my live store, and 2aef6790 has
since been edited by me to clear the false Failed. I preserved a complete snapshot of all
twelve original job records, their timeline.jsonl files, the full daemon.log and the
2aef6790 transcript, and can attach any of them on request.

Related

  • #91768 — Ctrl-X unbinds a session in the agents view. Filed alongside this one. Two of the

three job records discussed here (01eb53de, e31e0dfd) originate from that bug, which is
why they never ran; this report is only about how they were subsequently reported.

  • #83024 — background agents and tasks killed unexpectedly
  • #87140 — Esc in the main input kills running background agents

Claude Code Version

2.1.251

Platform

Claude subscription, CLI

Operating System

Linux (CachyOS, kernel 7.2.2)

Terminal/Shell

kitty / zsh

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗