Background-agent adoption never succeeds (0 of 7 attempts): live sessions marked Failed, reap and daemon death unlogged
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:
- Adoption never succeeds. Every
bg adoptline in my log reports `adopted=0
respawned=0`. Seven attempts, seventeen workers declared dead, zero ever recovered.
- Most daemon deaths are unlogged. Ten
daemon startlines, threeshutting down
lines. Seven daemon deaths leave no record of why.
- The reap itself is silent and its timestamp is misnamed.
daemon.logcontains 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, whosereapedMidWorkAt 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 itschildren 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.loghas zero "reap" lines, so the single most
important state transition for the user is invisible.
reapedMidWorkAtshould either mean what it says or be renamed, and a separate field
should record when the job was actually marked failed.
Failedin 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, 7bg adopt(alladopted=0 respawned=0, 17 workers), 3 `shutting
down, 0 occurrences of "reap" in daemon.log`.
reapedMidWorkAtequals astate:"working"entry in the job's owntimeline.jsonl.- All three affected job records were last written within 2 s of a daemon boot.
2aef6790was alive and running inference at20: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 at23: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"withinteractiveLineage: 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:
- Run background agents through
claude agentsacross several daemon restarts. grep 'bg adopt' ~/.claude/daemon.log— check whetheradopted=is ever non-zero.- Compare
daemon startcount againstshutting downcount to see the unlogged exits. - For any job showing
Failed, comparestate.json'supdatedAtagainst 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 the2aef6790 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
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗