[Bug]: Parent is never notified when a delegated child's provider-initiated run ends (e.g. after a background command finishes)#21772

opened9d agobyDdpearson2699

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. A parent thread (Claude Agent provider) calls delegate_task in mode: "async" for a Claude Agent child.
  2. In its turn, the child starts a long shell command with the provider's own background execution (Claude Code's Bash tool with run_in_background), says it will wait for the result, and ends the turn.
  3. T3 delivers that turn's completion to the parent as normal. task_status then shows status: "completed", workState: "result_available", hasPendingChildRuns: false. T3 has nothing to track: the background command lives in the provider, not in T3.
  4. The background command finishes. The provider wakes the child with its own "Command … finished" notification, and that starts a new run in the child's backing thread. No t3_thread_send or other T3 call created this run.
  5. The child finishes that run with a result intended for the parent, such as "built and verified; waiting for your decision before I push".

Expected behavior

The parent is woken with the later run's result, as it is now for follow-up runs started by t3_thread_send (#13490, fixed by #17696). The alternative is that the run is surfaced somehow, so a result produced in a delegated child thread is never silently left unread.

Actual behavior

The parent is never woken for runs the provider starts itself. The result exists only in task_status's latestTerminalRunId / latestTerminalSummary, so the parent sees it only if it happens to poll.

In one session, a child thread completed six such provider-woken runs over about 45 minutes, each ending at a "background command finished" wake. The last one ended with a request for a decision from the parent. The parent got no notification for any of them, and the child sat waiting until the user noticed about an hour later and asked why nothing was happening. A second child in the same session hit the same thing at the same time.

Impact

Major degradation or frequent failure

Version or commit

T3 Code Nightly 0.1.1, a build between 0.1.1-nightly.20261018.3315 and 0.1.1-nightly.20261019.3360. The app auto-updated to .3360 during the session, and the running process predates that install.

Environment

macOS 27.0.1. Parent and children: Claude Agent provider (claude-opus-5-5). Child thread runtime mode full-access.

Logs or stack traces

shell
1# task_status for the delegated task, read by the parent about an hour after the child's last run ended
2status: completed
3workState: result_available
4hasPendingChildRuns: false
5latestTerminalRunId: run:thread:<child-thread>:ordinal:34 # provider-woken run; no parent notification was delivered
6latestTerminalStatus: completed
7latestTerminalSummary: "... Nothing is pushed or posted yet; I'm waiting for your go-ahead. ..."
8
9# the child thread's activity timeline shows each later run beginning with a provider notification item, e.g.
10notification Command "Green run: focused suites then full unit suite" finished

Workaround

Each of these works around it:

  • The child calls t3_thread_send to the parent thread itself (mode: "queue") whenever it stops at a decision point or finishes, which wakes the parent.
  • The child waits on T3-tracked work (delegate_task) instead of provider background commands.
  • The parent polls task_status.

Related

#13490 is the same symptom for follow-up runs started by t3_thread_send, and it is fixed. This report covers runs that the provider starts on its own.

Note

Grok responding on behalf of Julius.

Thanks for the clear timeline. Confirmed on current main.

Delegated results reach the parent per task. When a child run ends, the server looks for the task that owns it (apps/server/src/orchestration-v2/Orchestrator.ts:10252-10258). It skips the original task once its result has already been delivered (Orchestrator.ts:10607-10617). The fix for #13490 creates a new task only for a message that a user or an MCP sender dispatches into the child (Orchestrator.ts:6940-6949). A run the provider starts by itself, such as after a background command finishes, gets no task, so nothing is delivered and the parent is never woken.

This isn't a duplicate of #16603. That issue covers the task finishing early while T3 can still see work running in the child. Here the task finished correctly, and the later work happens outside anything T3 tracks.

Accepting this as a bug. Your workarounds still apply for now: have the child message the parent when it needs a decision, or have the parent check task status.

Synced from GitHub

Another data point for this one, from 0.1.2-nightly.20261021.3486 (macOS, Claude Code 2.1.307, a Sonnet 5.5 child at low effort). In my case the parent got the wrong result, not only a missing wake, so it may be worth checking against the open fix in #21813.

What I ran (my agent drove the MCP calls):

  1. I used delegate_task to start a Claude child. It ran sleep 45 with native Bash background execution, ended the turn, and was to reply CANARY-1 when the job finished.
  2. While the job was still pending, two t3_thread_send calls to the child with mode: "queue": /compact, then a note asking it to reply CANARY-2.

The child's runs, in order: run 1 ended with the job pending, run 2 was the compaction, run 3 replied CANARY-2, and run 4 started from the background-task notification and replied CANARY-1. Both queued turns finished before the background job did.

What the parent got: one wake for the original task, with summary CANARY-2. task_status later showed latestTerminalSummary: "CANARY-1", and no second wake came. So the original task was published with the queued turn's text as its result, and I recovered the requested answer by reading task_status, without receiving another wake.

My guess at the mechanism from reading main at ed9b7ca9 (not confirmed with finalizer timestamps): the #22709 listener rechecks the task for finalization when the background roster empties (Orchestrator.ts L11879-L11907), and delegatedTaskProgress picks the newest terminal work run as the result (subagentProjection.ts L241-L268). In the provider log the roster emptied at 23:29:53.089Z and the wake turn started at 23:29:53.882Z. That ordering is consistent with the finalizer seeing the queued CANARY-2 turn as the newest terminal run before the wake turn was registered. After that the finalizer skips a task that already has both a result and a result transfer from that child (Orchestrator.ts L10886-L10924).

Expected: the parent gets CANARY-1 as the task's result, either because publication waits for the provider's wake turn or because the later answer is delivered on its own. Queued user or maintenance text shouldn't stand in for the task's answer.

A queued note without the /compact is probably enough to reproduce it, but I only ran the version above.

Synced from GitHub

Note

Claude Opus 5.5 responding on behalf of @snnbotchway.

This still happens on 0.1.2-nightly.20261022.3541 (Ubuntu Linux, T3 server as a user service). Parent and children are Claude Agent, claude-opus-5-5. The build does not include #21813.

In one overnight run, 4 of about 25 async delegate_task children hit it. Each child started its final checks with Bash run_in_background and ended run 1 with an interim text ("checks are running, I will send the full report"). The parent got only that interim text.

The worst case, from the child's run list:

  • Run 1 ended at 03:20 UTC. The parent was notified at 03:23 with the interim text.
  • Runs 2 to 4 were provider wakes after background commands finished. Run 4 ended at 03:28 with the final report (head SHA, all checks passed).
  • At 04:03 the parent was woken by a different child's completion. Nothing told it that this task had a newer result.
  • The parent read latestTerminalSummary only at 07:51, when the user asked. The result had waited about 4.5 hours.

task_status at that time showed status: completed, hasPendingChildRuns: false, and latestTerminalRunId at ordinal:5.

For now we tell delegated children to run their checks in the foreground with a long timeout, so the result is in run 1.

Synced from GitHub

This was my number one issue when I ran Matt Pocock's /retro skill.

Synced from GitHub

Note

Claude Opus 5.5 responding on behalf of Kombuchelada.

Another data point from 0.1.2 stable (macOS, Claude Code 2.1.310). Parent and children are Claude Agent, claude-opus-5-5 at high effort.

  • A parent started three async delegate_task children. Each child's last step was a test run of about 15 minutes. That's too long for one foreground Bash call, so the child started it with run_in_background and ended its turn with an interim "waiting on the tests".
  • That interim text became the task result. When the run finished, the child woke, completed the work (a PR marked ready) and wrote its final report. The parent was never woken with it.
  • Two of the three children hit this within an hour, and we found the finished work only by reading the child threads. On Linux (0.1.2, Claude Code 2.1.309), an earlier child did the same with a 5-minute background test run.

Each child's earlier turns ended while its own Agent subagents were running, and those correctly kept the task open. So the trigger is specifically a background command, and any step longer than the Bash timeout forces one.

Synced from GitHub

Note

Claude Opus 5.5 posting on behalf of @dilbagh

Same outcome on 0.1.2 stable, two children in one parent thread: each child's final report after a background CI watch never woke the parent, and the work sat idle for about 2 h and then 1 h 40 min until the user asked for a status. In both cases the trigger was the race in #24297 (timestamps there), so a fix that delivers the later runs' results would have covered both.