Skip to content

Subagents can shut down without delivering results; fork_turns none scouts acted as orchestrators #26822

Open

Description

@Allmight97

Summary

In Codex Desktop / MultiAgentV2, a parent thread spawned three read-only scout subagents with fork_turns: "none". The parent never received a final answer or mailbox result from any child. Repeated wait_agent calls timed out on schedule; list_agents later showed the children as shutdown; close_agent then returned thread <id> not found.

Local child rollout logs show the children were not merely idle. Despite self-contained read-only scout prompts, they appear to have acted like orchestration agents: they called wait_agent, attempted close_agent on sibling scouts, emitted commentary about other scouts not returning, and then their turns were interrupted/aborted. None delivered the requested scout findings to the parent.

This makes subagents unreliable for long planning/review/scout workflows: the parent cannot distinguish "still running," "shutdown without result," "lost mailbox result," "thread not found," or "child misinterpreted inherited orchestration context."

Environment

  • Variant: Codex Desktop / app-side multi-agent tools
  • CLI visible locally: codex-cli 0.137.0
  • Platform: macOS 26.6, Darwin 25.6.0 arm64
  • Account/subscription: ChatGPT Pro
  • Parent rollout/session:
    • /Users/jstar/.codex/sessions/2026/06/06/rollout-2026-06-06T13-43-41-019e9ead-5b80-7e40-8f53-ed9e915b86a4.jsonl
    • session id 019e9ead-5b80-7e40-8f53-ed9e915b86a4
  • Child rollout/session ids:
    • runtime/jobs scout: 019e9eb0-2d48-7dc3-93c8-ba9241c99566
    • frontend workflows scout: 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8
    • docs/contracts scout: 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac

Reproduction shape

This was observed during a repo planning task where the parent tried to fan out read-only exploration scouts.

  1. In a parent Codex Desktop thread, first attempt to spawn multiple scouts with agent_type plus a full-history fork.
  2. Observe spawn validation error:
    • Full-history forked agents inherit the parent agent type, model, and reasoning effort; omit agent_type, model, and reasoning_effort, or spawn without a full-history fork.
  3. Retry with self-contained prompts and fork_turns: "none":
    • scout_runtime_jobs, agent_type: "explorer"
    • scout_frontend_workflows, agent_type: "explorer"
    • scout_docs_contracts, agent_type: "explorer"
  4. Attempt a fourth scout. It fails with:
    • collab spawn failed: agent thread limit reached
  5. Parent waits repeatedly:
    • wait_agent({"timeout_ms":30000}) -> timed out
    • wait_agent({"timeout_ms":60000}) -> timed out
    • wait_agent({"timeout_ms":90000}) -> timed out
    • wait_agent({"timeout_ms":180000}) -> timed out
  6. Parent checks agents:
    • Early list_agents showed the three scouts as running.
    • Later list_agents showed the three scouts as shutdown.
    • No final answer/mailbox payload had arrived in the parent.
  7. Parent tries to close them and gets:
    • collab tool failed: thread 019e9eb0-2d48-7dc3-93c8-ba9241c99566 not found
    • collab tool failed: thread 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8 not found
    • collab tool failed: thread 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac not found

Evidence from parent rollout

From parent rollout /Users/jstar/.codex/sessions/2026/06/06/rollout-2026-06-06T13-43-41-019e9ead-5b80-7e40-8f53-ed9e915b86a4.jsonl:

  • Lines 26-29: first spawn attempts with agent_type + fork_turns: "all"; all returned the full-history fork validation error.
  • Lines 38-45: retry with fork_turns: "none"; three scouts spawned successfully and the fourth returned agent thread limit reached.
  • Lines 262-263: wait_agent 30s timeout.
  • Lines 286-287: wait_agent 60s timeout.
  • Lines 292-293: wait_agent 90s timeout.
  • Lines 298-299: wait_agent 180s timeout.
  • Lines 268-269: list_agents showed the three scouts as running.
  • Lines 304-309: close_agent returned thread <id> not found for all three child ids.
  • Lines 314-315: list_agents showed the three scouts as shutdown, still without any parent-delivered result payload.

Evidence from child rollouts

The child rollouts suggest this was not just slow/empty execution. The children appear to have drifted into orchestrator behavior and then aborted/interrupted.

  • Docs/contracts scout, child session 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac:
    • called wait_agent({"timeout_ms":30000}), timed out
    • emitted commentary about scout threads still running
    • attempted close_agent on sibling scouts
    • close outputs reported aborted by user after 0.1s
    • turn ended with reason: "interrupted", duration about 279s
  • Frontend workflows scout, child session 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8:
    • called wait_agent({"timeout_ms":60000}), timed out
    • emitted commentary that scout agents did not return
    • attempted to close sibling/current scouts
    • one close output reported thread ... not found; another was aborted by user after 0.1s
    • turn ended with reason: "interrupted", duration about 326s
  • Runtime/jobs scout, child session 019e9eb0-2d48-7dc3-93c8-ba9241c99566:
    • called wait_agent({"timeout_ms":10000}), timed out
    • emitted commentary that the frontend/doc scouts had shut down
    • attempted close_agent on itself
    • close output reported aborted by user after 0.1s
    • turn ended with reason: "interrupted", duration about 375s

Expected behavior

  • A child spawned with fork_turns: "none" and a self-contained read-only prompt should treat that prompt as the active task and should not start coordinating sibling agents unless explicitly instructed.
  • If a child shuts down, is interrupted, or aborts before producing a normal final answer, the parent should receive a structured terminal event through wait_agent/mailbox.
  • wait_agent, list_agents, and close_agent should agree on lifecycle state or return a structured explanation of the mismatch.
  • thread <id> not found should not be the only close/readback signal for a thread that was previously spawned and visible through list_agents.
  • Thread capacity should be discoverable before spawn, or spawn_agent should return enough status on agent thread limit reached to recover cleanly.

Actual behavior

  • The parent received no usable scout content and no child final-answer payload.
  • wait_agent only returned timeouts, even though child turns later ended/interrupted.
  • list_agents transitioned from running to shutdown, but the parent still received no terminal child result.
  • close_agent returned thread <id> not found for each child.
  • Child rollouts show children calling orchestration tools (wait_agent, close_agent) instead of simply completing their assigned scout prompts.

Related issues checked

I did not find an exact duplicate for this combined failure mode: child shutdown/no parent-delivered final result + not found cleanup/readback + fork_turns: "none" scouts acting as orchestrators.

Adjacent issues:

Impact

This makes subagents brittle for exactly the workflows where they are most valuable: parallel repo scouting, review/audit variance reduction, long-running research branches, and delegated planning. The parent thread cannot rely on subagent output unless a final payload actually arrives, and the failure mode consumes time/context while leaving no trustworthy result.

For user-facing Codex Desktop behavior, this feels like subagents silently disappearing or becoming confused about their role. It also makes it hard to file precise bug reports because parent-visible state and child-local state disagree.

Suggested fix direction

  • Strengthen the active task boundary for spawned children, especially fork_turns: "none" children with role-scoped prompts. Parent/team orchestration instructions should not cause a child to manage sibling agents unless that is explicitly delegated.
  • Always deliver a child terminal state to the parent mailbox, even if there is no final answer: completed, interrupted, aborted, shutdown_without_result, not_found_after_spawn, etc., with child thread id and last known status.
  • Make wait_agent able to surface terminal status updates for shutdown/interrupted children, not only final answer payloads.
  • Reconcile list_agents and close_agent states. If a listed/shutdown child has no live thread, return a structured already_shutdown / not_found_but_spawn_was_recorded signal instead of a generic thread not found failure.
  • Expose capacity/status preflight before spawning, or include active capacity and live child list in the agent thread limit reached response.
  • Add regression coverage for:
    • fork_turns: "none" child with a narrow scout prompt must not call wait_agent/close_agent unless the prompt asks it to.
    • child interrupted after startup must generate a parent-visible terminal event.
    • parent wait_agent must observe child terminal events.
    • list_agents/close_agent lifecycle consistency after child shutdown or interrupted turn.

Activity

  1. github-actions commented on Jun 6, 2026

    @github-actions
    Contributor
  2. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    subagentIssues involving subagents or multi-agent features
    model-behaviorIssues related to behaviors exhibited by the model
    on Jun 6, 2026
  3. aliwatters commented on Jul 14, 2026

    @aliwatters

    Additional reproduction on Codex CLI 0.144.3 in the Desktop/MultiAgent runtime:

    1. A parent agent dispatched several self-contained implementation workers into
      separate clean Git worktrees. Each prompt was narrow and did not request
      orchestration or sibling coordination.
    2. Three workers remained running for several minutes without returning a
      terminal payload, handoff, test result, or filesystem edit. The parent only
      received repeated wait_agent timeouts.
    3. The parent interrupted the workers after verifying their worktrees were
      clean. list_agents continued to show the children as interrupted.
    4. A subsequent spawn_agent failed with collab spawn failed: agent thread limit reached, leaving no way to launch a fresh recovery worker in the same
      parent session.

    This matches the combined failure here: children can fail to deliver a useful
    terminal result, and retained interrupted/completed child threads exhaust the
    spawn quota. The parent cannot recover by starting a fresh worker even when no
    child has touched the worktree.

    Control: a minimal standalone codex exec --ephemeral --sandbox read-only
    probe completed successfully in the same environment, so this observation is
    about the MultiAgent lifecycle/capacity path rather than general model
    connectivity.

    Expected recovery behavior: every interrupted or shutdown child should emit a
    parent-visible terminal event and release its spawn slot; alternatively the
    parent needs a supported cleanup/retry path with capacity diagnostics.

  4. 0xdeafbeef commented on Jul 19, 2026

    @0xdeafbeef

    Additional source-level evidence for this issue:

    Current main at 0fb559f0 appears to contain a concrete gap in the MultiAgentV2 lifecycle:

    As a result, if a V2 child disappears without emitting TurnComplete or TurnAborted, no event reaches the parent input queue and wait_agent cannot observe the child’s death.

    More fundamentally, the V2 wait_agent API has no child identifier or target list: its only argument is timeout_ms. This prevents the handler from validating the child before blocking or returning NotFound for a removed thread.

    At minimum, a targetless wait should return immediately when the parent has no live descendants and no pending mailbox activity. Preferably, the API should accept explicit child targets and return their current terminal or NotFound state before subscribing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingmodel-behaviorIssues related to behaviors exhibited by the modelsubagentIssues involving subagents or multi-agent features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions