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

Open 💬 6 comments Opened May 31, 2026 by MingyooLee
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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

  • Related/possibly regressed from: #20543
  • Related fork/default behavior issue: #20077
  • Related spawned-agent context prompt issue: #17323
  • Related inherited parent-context behavior: #24150
  • Split sibling-leakage issue: #26130

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.

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 1 month ago

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

  • #24150

Powered by Codex Action

MingyooLee · 1 month ago

Thanks for the duplicate check.

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

  • #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.

flamerged · 1 month ago

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.

  1. 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.

  1. 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.

hipvlady · 1 month ago

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.

MingyooLee · 1 month ago

Thanks, agreed. I split the two reproduction paths.

  • This issue is now focused on the no-fork task-delivery / role-misclassification bug: spawn_agent(..., fork_turns: "none") can deliver the child task as an assistant / commentary mailbox envelope instead of a user/task message.
  • The parallel sibling prompt-envelope leakage has been split into #26130 with its own focused reproduction.

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

MingyooLee · 1 month ago

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.