Skip to content

MultiAgentV2 spawn_agent with fork_turns none delivers task as assistant/commentary mailbox envelope #25458

Open

Description

@MingyooLee

Summary

In Codex Desktop / MultiAgentV2, spawn_agent(..., fork_turns: "none") creates the child thread, but the initial message can be recorded in the child rollout as an assistant/commentary JSON mailbox envelope instead of a user/task message.

The child may then treat the assigned task as prior assistant output or context, acknowledge workspace instructions, return a generic AGENTS/project acknowledgement, or execute unintended orchestration instead of following the delegated prompt.

This issue is now focused on the single-child no-fork task-delivery / role-misclassification bug. The parallel sibling prompt-envelope leakage originally included here has been split into: #26130.

Environment

  • Variant: Codex Desktop
  • Session originator in rollout metadata: Codex Desktop
  • CLI version in rollout metadata from the original reproduction: 0.135.0-alpha.1
  • Additional local scan evidence also observed with Codex CLI/Desktop metadata around 0.136.0-alpha.2
  • Platform: macOS
  • Date reproduced: 2026-06-01 KST
  • Subscription/model: ChatGPT/Codex Desktop session using GPT-5 family models

Related Issues

I do not think this is an exact duplicate of #24150 because this no-fork prompt-delivery failure reproduces with fork_turns: "none", where the child should not inherit the parent thread history.

Expected Behavior

For spawn_agent with fork_turns: "none":

  1. The child should receive the message argument as its initial task/user-equivalent instruction.
  2. The delegated task should not be visible only as an assistant/commentary mailbox envelope.
  3. A child asked to reply with an exact token should either reply with that token or report a real failure, not return a generic workspace acknowledgement.

For spawn_agent with fork_turns: "all":

  1. The child may receive parent history, but the newly supplied message should still be the active task boundary, not just another assistant/commentary envelope inside inherited context.

Actual Behavior

Observed child rollouts show the task passed as message recorded as:

{
  "type": "response_item",
  "payload": {
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "output_text",
        "text": "{\"author\":\"/root\",\"recipient\":\"/root/exp1_seq_b\",\"other_recipients\":[],\"content\":\"BLACKBOX_PROBE_B. Reply exactly: EXP1_SEQ_B_ONLY. Do not use tools. Do not mention any other prompt.\",\"trigger_turn\":true}"
      }
    ],
    "phase": "commentary"
  }
}

The child can then return a generic workspace/AGENTS acknowledgement instead of following the assigned task.

Minimal Reproduction Shape

From a Codex Desktop session with subagents enabled, run a single no-fork child probe:

{
  "task_name": "exp1_seq_b",
  "fork_turns": "none",
  "message": "BLACKBOX_PROBE_B. Reply exactly: EXP1_SEQ_B_ONLY. Do not use tools. Do not mention any other prompt."
}

Observed child rollout sequence:

L2 event_msg task_started
L3 response_message role=developer phase=None ...
L4 response_message role=user phase=None ... workspace/project instructions
L6 response_message role=assistant phase=commentary text={\"author\":\"/root\",\"recipient\":\"/root/exp1_seq_b\",...\"content\":\"BLACKBOX_PROBE_B...\"}
L7 event_msg agent_message EXP1_SEQ_B_ONLY
L8 response_message role=assistant phase=commentary text=EXP1_SEQ_B_ONLY
L10 event_msg agent_message generic workspace acknowledgement
L11 response_message role=assistant phase=final_answer generic workspace acknowledgement
L13 event_msg task_complete

The important part is that the task envelope appears as role=assistant, phase=commentary, not as a user/task message.

Fresh Follow-up Probes

Fresh follow-up probes used exact-token prompts such as:

BUGPROBE_SINGLE_NONE_1001. Reply exactly: BUGPROBE_SINGLE_NONE_DONE. Do not use tools.
BUGPROBE_REVIEWER_NONE_1001. Minimal audit probe only. Reply exactly: BUGPROBE_REVIEWER_NONE_DONE. Do not use tools.
BUGPROBE_ALL_1001. Reply exactly: BUGPROBE_ALL_DONE. Do not use tools.

Observed results:

single default, fork_turns none:
  prompt line: assistant/commentary JSON envelope
  final answer: generic AGENTS/project acknowledgement, not requested exact token

reviewer role, fork_turns none:
  prompt line: assistant/commentary JSON envelope
  final answer: generic AGENTS/project acknowledgement, not requested exact token

default, fork_turns all:
  inherited large parent context
  new task prompt appeared very late as assistant/commentary
  child continued parent workflow, used tools, and spawned a nested subagent
  parent wait timed out; close reported previous_status=running

Additional Local Scan

After #25458 was opened, I scanned recent local Codex session JSONL records in a redacted way. The scan found:

subagentSessionsWithRecordsAfterIssue=373
subagentWithMailboxAfterIssue=372
subagentWithUserTaskLikeAfterIssue=0
mailboxTotalAfterIssue=684
turnAbortedInterruptedAfterIssue=92
errorEventsAfterIssue=0
streamErrorEventsAfterIssue=0

Interpretation: the assistant/commentary mailbox shape is not a one-off in my local traces. I am not attaching raw rollout logs because they contain private local paths and conversation content.

Impact

This makes multi-agent workflows unreliable:

  • review agents can ignore the actual review assignment and only acknowledge context;
  • children can execute unintended orchestration if they treat mailbox envelopes as prior assistant output;
  • fork_turns: "all" can produce timeout/running/nested-spawn behavior because the child continues parent workflow instead of treating the new message as active task;
  • parent-side wait_agent / close_agent results can appear misleading when the child completed the wrong task or is still running wrong-context work.

What I Am And Am Not Claiming

Confirmed by black-box rollout evidence:

  • the initial spawn message is repeatedly model-visible as an assistant/commentary JSON envelope;
  • fresh no-fork probes can ignore exact-token instructions and return generic acknowledgements;
  • inherited context can cause unexpected tool use and nested spawning.

Not confirmed from black-box evidence alone:

  • I do not know the exact internal function or line that converts/routes the spawn message;
  • I do not have evidence yet of a clean child completing the correct task while wait_agent loses the notification;
  • I am not claiming a confirmed process crash.

Suggested Regression Coverage

  1. With multi_agent_v2 enabled and fork_turns: "none", spawn a child with Reply exactly: TOKEN.
  2. Assert the child final is TOKEN.
  3. Assert the delegated task is delivered as a user/task input, not only as an assistant/commentary mailbox JSON envelope.
  4. Repeat for codex-ultrawork-reviewer and a default child role, because both showed the same envelope shape in black-box traces.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    subagentIssues involving subagents or multi-agent features
    on May 31, 2026
  2. github-actions commented on May 31, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  3. MingyooLee commented on May 31, 2026

    @MingyooLee
    Author

    Thanks for the duplicate check.

    I reviewed #24150. It looks related, but I do not think this issue is an exact duplicate:

    • fork_context:true subagents continue parent-thread work instead of following delegated prompt #24150 is about fork_context: true / inherited parent-thread context boundaries, where the child continues parent-thread work instead of treating the delegated prompt as active.
    • This issue reproduces with fork_turns: "none", where there should be no inherited parent history, and the initial spawn_agent task is still recorded as an assistant / commentary JSON envelope rather than a user/task message.
    • This issue also includes a second symptom: in same-turn parallel spawns via multi_tool_use.parallel, one child rollout can contain the sibling child's prompt envelope despite fork_turns: "none".

    So I agree they are in the same subagent/task-boundary area, but this report covers a narrower no-fork prompt-delivery problem plus parallel sibling prompt leakage.

  4. flamerged commented on Jun 2, 2026

    @flamerged

    I have another anonymized data point that supports this issue and adds two
    pieces of evidence from a larger local session scan.

    I checked the current #25458/#23296/#17523 text on 2026-06-02. #25458 already
    covers the core no-fork assistant/commentary delivery bug, so I am framing this
    as additional evidence rather than a new issue. The added signal here is:

    • v2-disabled control restores normal user/task delivery;
    • child_agents_md=false does not fix v2 delivery;
    • assign_task follow-up uses the same assistant/commentary mailbox path;
    • aggregate scan found no structured child error/stream_error events;
    • wait/close correlation explains many apparent child deaths as parent-induced
      interrupted aborts.

    Environment:

    • Codex CLI: codex-cli 0.136.0
    • Platform: macOS arm64
    • codex features list reported:
      • multi_agent: stable true
      • multi_agent_v2: under development true
      • child_agents_md: under development true
      • enable_fanout: under development true
    • codex features list --disable multi_agent_v2 reported:
      • multi_agent_v2: under development false

    I am not attaching raw rollout logs because they contain private local paths and
    conversation content. The details below are reduced to roles, event shapes,
    aggregate counts, and exact-token probe outcomes.

    Controlled probes

    V2 disabled: exact-token child task succeeds

    Run shape:

    codex exec --json -c features.multi_agent_v2.enabled=false ...
    

    Child task:

    Reply with exactly CONFIG_V2_DISABLED_OK.
    

    Observed child rollout shape:

    developer/system context
    user: AGENTS/project instructions
    user: Reply with exactly CONFIG_V2_DISABLED_OK.
    assistant final: CONFIG_V2_DISABLED_OK
    event: task_complete
    

    No assistant mailbox envelope preceded the child response. This shows that
    -c features.multi_agent_v2.enabled=false changes actual child task delivery,
    not just feature-list display.

    Clean sanitized exact-token contrast

    I also ran a fresh temporary-workspace contrast with only a generic AGENTS.md.

    With v2 enabled, the exact-token task succeeded, but the task still arrived as
    assistant/commentary mailbox JSON:

    user: AGENTS/project instructions
    assistant/commentary:
      {"author":"/root","recipient":"/root/<child>","content":"Reply with exactly CLEAN_V2_ENABLED_OK.","trigger_turn":true}
    assistant final: CLEAN_V2_ENABLED_OK
    event: task_complete
    

    With v2 disabled, the exact-token task also succeeded, and the task arrived as a
    normal user/task message:

    user: AGENTS/project instructions
    user:
      task_name: <child>
      Reply with exactly CLEAN_V2_DISABLED_OK.
    assistant final: CLEAN_V2_DISABLED_OK
    event: task_complete
    

    So the clean probe is not a standalone task-loss repro. It is a sanitized
    confirmation of the role/phase mismatch: v2 enabled exposes the delegated task
    as assistant/commentary mailbox JSON, while v2 disabled exposes it as a normal
    child task.

    V2 enabled, child_agents_md=false: exact-token child task still fails

    Run shape:

    codex exec --json -c features.child_agents_md=false ...
    

    Feature state:

    child_agents_md: false
    multi_agent_v2: true
    

    Child task:

    Reply with exactly CHILD_AGENTS_MD_DISABLED_OK.
    

    Observed child rollout shape:

    developer/system context
    user: AGENTS/project instructions
    assistant/commentary:
      {"author":"/root","recipient":"/root/<child>","content":"Reply with exactly CHILD_AGENTS_MD_DISABLED_OK.","trigger_turn":true}
    assistant final: generic workspace/project acknowledgement
    event: task_complete
    

    The delegated task was not delivered as a user/task message and was not
    followed. This suggests the failure is in the v2 task-delivery path, not merely
    the AGENTS rendering option.

    assign_task follow-up uses the same delivery shape

    Probe shape:

    Initial child task: Reply with exactly SPAWN_PHASE_OK.
    Follow-up assign_task: Reply with exactly ASSIGN_RECOVERY_OK.
    

    Observed child rollout shape:

    turn 1:
      user: AGENTS/project instructions
      assistant/commentary:
        {"author":"/root","recipient":"/root/<child>","content":"Reply with exactly SPAWN_PHASE_OK.","trigger_turn":true}
      assistant final: generic AGENTS/workspace acknowledgement
    
    turn 2:
      assistant/commentary:
        {"author":"/root","recipient":"/root/<child>","content":"Reply with exactly ASSIGN_RECOVERY_OK.","trigger_turn":true}
      assistant final: generic "ready for next task" response
    

    So assign_task can trigger another child turn, but it does not repair the
    message-role/task-boundary issue. The follow-up also arrives as
    assistant/commentary mailbox JSON.

    Aggregate local scan

    Read-only analyzer scope:

    • JSONL files scanned: 756
    • Session metadata records: 749
    • Subagent sessions: 370
    • JSON parse/read errors: 0

    Task-delivery shape before the first child agent message:

    • assistant_mailbox_before_first_agent: 320
    • user_task_before_first_agent: 30
    • no_messages_before_first_agent: 15
    • context_only_before_first_agent: 5

    Assistant mailbox envelopes across all subagent turns:

    • Total assistant mailbox envelopes in subagent sessions: 778
    • Assistant mailbox envelopes after the first child agent message: 454
    • trigger_turn=true envelopes: 736
    • trigger_turn=false envelopes: 37
    • Subagents with at least one assistant mailbox envelope: 325 / 370
    • Subagents with at least one post-first-response assistant mailbox envelope:
      219 / 370

    Outcome highlights:

    • V2 mailbox completions that were acknowledgement/orientation or non-exact
      content: 127
    • Structured error events in subagent sessions: 0
    • Structured stream_error events in subagent sessions: 0
    • Subagent turn_aborted events: 192
    • Subagent turn_aborted reasons: interrupted: 192

    Interpretation:

    • The assistant/commentary mailbox path is not just an initial-spawn artifact.
      It also appears in later inter-agent traffic such as assign_task.
    • The dominant failure pattern looks like wrong task-delivery semantics plus
      parent interruption, not random child runtime crashes.

    Wait/close lifecycle evidence

    I also correlated parent close_agent outputs with child abort events:

    • previous_running close outputs mapped to known child subagents: 112
    • Of those, children with turn_aborted: 102
    • Nearest prior wait output before previous_running close:
      • timed_out_true: 81
      • none: 13
      • tool_aborted_by_user: 12
      • timed_out_false: 6
    • Absolute time from close output to child turn_aborted:
      • <=1s: 101
      • <=5s: 1
      • unknown: 10

    This makes many child failures look like "the subagent died", but the structured
    events show interrupted immediately after the parent closed a still-running
    child. A wait_agent timeout appears easy for the parent agent to misinterpret
    as failure, then close_agent turns it into an abort.

    State DB note

    The local thread_spawn_edges table had:

    • closed: 307
    • open: 57

    All 364 rows mapped to child rollout records. Among the 57 open rows:

    • task_complete_nonempty_agent_final: 33
    • turn_aborted: 14
    • agent_message_without_task_complete: 6
    • metadata_only: 4

    So thread_spawn_edges.status=open is useful historical linkage, but it is not
    a reliable live-child indicator.

    Suggested regression coverage

    1. With multi_agent_v2 enabled and fork_turns: "none", spawn a child with
      Reply exactly: TOKEN; assert the child final is TOKEN and the task is
      delivered as a user/task input, not only assistant/commentary mailbox JSON.
    2. After the child gives an initial response, call assign_task with
      Reply exactly: TOKEN2; assert the child final is TOKEN2 and the follow-up
      is not only assistant/commentary mailbox JSON.
    3. Create a child that runs longer than a short wait_agent deadline; assert
      wait_agent timeout is represented as "no mailbox update yet", not child
      failure, and that closing a running child is explicitly surfaced as an abort.

    This evidence seems directly related to this issue. It also overlaps with the
    symptoms in #23296, but the key new details here are:

    • v2-disabled control restores normal user-task delivery;
    • child_agents_md=false does not fix v2 delivery;
    • assign_task uses the same assistant/commentary mailbox path;
    • structured event scan found no subagent error/stream_error events, only
      turn_aborted with reason interrupted.
  5. hipvlady commented on Jun 3, 2026

    @hipvlady

    The role-misclassification and sibling-envelope leakage you're describing are two distinct failure modes in spawn_agent orchestration — worth keeping them separate for the reproduction path. I'm seeing the same structural shape (agent executing against wrong context without surfacing it) in parallel subagent patterns across LangGraph and Claude Code as well. The reproduction isolation you've done here is useful cross-framework evidence.

  6. changed the title [-]MultiAgentV2 spawn_agent initial task is recorded as assistant/commentary and parallel child prompts leak[/-] [+]MultiAgentV2 spawn_agent with fork_turns none delivers task as assistant/commentary mailbox envelope[/+] on Jun 3, 2026
  7. MingyooLee commented on Jun 3, 2026

    @MingyooLee
    Author

    Thanks, agreed. I split the two reproduction paths.

    I left the wait_agent / close_agent lifecycle observations as adjacent/non-scope notes rather than making them part of either main repro path.

  8. MingyooLee commented on Jun 3, 2026

    @MingyooLee
    Author

    Adding a concise surface clarification from a clean CLI probe.

    I originally encountered this while using the Codex Desktop app, but I also confirmed the same role/phase mismatch through Codex CLI codex exec --json on codex-cli 0.136.0.

    Probe shape:

    spawn_agent(..., fork_turns: "none")
    child task: reply exactly CLI_SINGLE_V2_OK
    

    Observed with multi_agent_v2 enabled:

    assistant/commentary:
      {"author":"/root","recipient":"/root/<child>","content":"TASK: Reply exactly CLI_SINGLE_V2_OK...","trigger_turn":true}
    assistant final: CLI_SINGLE_V2_OK
    

    Observed with multi_agent_v2 disabled for the same shape:

    user:
      TASK: Reply exactly CLI_SINGLE_V2_DISABLED_OK...
    assistant final: CLI_SINGLE_V2_DISABLED_OK
    

    So the CLI probe did not necessarily show task loss in this exact-token case, but it did reproduce the task-delivery shape mismatch: v2 enabled exposes the delegated task as an assistant / commentary mailbox envelope, while the v2-disabled control exposes it as a normal user/task message.

    I also tried a same-turn two-child CLI parallel probe. In that clean run, each child saw only its own token, so I am not treating that as a CLI reproduction of the sibling-envelope leakage tracked separately in #26130.

  9. magicVspace commented on Aug 9, 2026

    @magicVspace

    Additional Windows reproduction (2026-08-09):

    • Surface: Codex Desktop 26.803.5235.0.
    • A controlled spawn_agent(..., fork_turns: "none") probe was run with two non-Codex custom roles.
    • The local OpenAI-compatible loopback gateway was healthy (/usage returned HTTP 200, token usage increased, and both roles produced model text), but the children did not receive/use the supplied run/seat/round task payload. One replacement child explicitly reported that the parent payload was absent.
    • Adding a fail-closed delivery guard stopped unintended repository exploration, but did not restore the missing task envelope.
    • Control: the same parent-side exact-token delivery pattern succeeded with a Codex Luna custom role.

    This separates the layers as: gateway transport PASS, model inference PASS, non-Codex custom-role task-envelope delivery FAIL. The current workaround is Codex-Luna-only routing; non-Codex roles remain excluded until an exact-token plus payload-hash receipt passes.

    I found no release note indicating that 0.147.0 fixes this no-fork delivery path. I can retest after a candidate build. No credentials, raw logs, private paths, task/thread IDs, or provider configuration are included here.

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 workingsubagentIssues 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