Skip to content

Forked Worker Inherits Parent User Intent and Misinterprets It as Direct Instruction (Recursive Delegation Attempt) #13491

Open

Description

@khaled-wsa

What version of Codex CLI is running?

codex-cli 0.107.0

What subscription do you have?

Pro

Which model were you using?

gpt-5.3-codex

What platform is your computer?

No response

What terminal emulator and version are you using (if applicable)?

No response

What issue are you seeing?

When spawning a worker with fork_context: true, the worker can incorrectly treat the parent thread’s last user message (addressed to orchestrator) as if it were addressed to the worker. In this case, the user told the orchestrator to “send a subagent,” and the worker then tried to do that itself, overriding its assigned implementation instructions.

What steps can reproduce the bug?

  1. In parent thread, user says: “send a subagent to do X.”
  2. Orchestrator spawns worker with fork_context: true and explicit implementation instructions.
  3. Observe worker behavior: it interprets the inherited user message as instruction to itself and attempts further delegation instead of implementing X.

What is the expected behavior?

  • Worker should follow only the explicit task payload sent to it by the orchestrator.
  • Worker should not reinterpret parent-level user intent as its own command stream.
  • Worker must not attempt orchestration actions (e.g., spawning more agents) unless explicitly supported and instructed.

Additional information

Suggested fix:

  • On spawn with fork_context, enforce an instruction boundary:
    • Parent user messages should be treated as historical context, not active directives for worker.
    • Worker should execute only orchestrator-provided task payload as authoritative.
  • Add role guardrails:
    • Block recursive delegation intents in worker role by default.
  • Add lint/diagnostic signal:
    • Warn when worker output includes orchestrator-only actions (spawn_agent, “launch subagent”, etc.).

Activity

  1. added
    CLIIssues related to the Codex CLI
    model-behaviorIssues related to behaviors exhibited by the model
    on Mar 4, 2026
  2. github-actions commented on Mar 4, 2026

    @github-actions
    Contributor

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

    Powered by Codex Action

  3. jif-oai commented on Mar 4, 2026

    @jif-oai
    Contributor

    Hi, could you /feedback from such a forked worker and send me the session ID?

  4. khaled-wsa commented on Mar 4, 2026

    @khaled-wsa
    Author

    Hi, could you /feedback from such a forked worker and send me the session ID?

    Hi. I lost the session, but I took a screenshot from the agent thread after running /agent and opening the thread: https://i.imgur.com/eKnvRGR.png

    In the screenshot, the first message shown is the orchestrator’s instructions to the worker agent. Shortly after, the orchestrator interrupts with another message. As you can see, the worker then attempts to launch a subagent, but it doesn’t have permission to do so, so it ends up echoing: echo "Launching subagent not possible from shell".

  5. timurkhakhalev commented on Mar 19, 2026

    @timurkhakhalev

    Yes, happened to me many times.

    Here is my story:

    codex agent's context fork = true feature is really misleads spawned agents.
    I discussed a big epic task with the main agent, then asked it to decompose epic into tasks, then asked it to spawn agents (with context fork = true) for each task and create files for each of these tasks.

    Then each spawned agent with forked context thought he is the orchestrator and each of them tried to launch new agents! 😆

    Pic is related. I have restrictions on agents max depth = 1 and spawn_agent tool is not available for them, so they're tried to use bash to spawn agents 😭

    Image
  6. grablair commented on Mar 21, 2026

    @grablair

    I am repeatedly getting subagents that are ignoring the fork directive:

    You are the newly spawned agent. The prior conversation history was forked from your parent agent. Treat the next user message as your new task...

    And instead inheriting the parent context and acting as the parent, resulting in agents recursively spawning agents, essentially becoming a useless proxy agent and confusing the root agent.

    See thread ID: 019d11aa-2f45-7813-bd18-f217fd22e335 (I've sent several feedbacks from several subagents for this thread)


    The parent agent sent this initial message (after any built in spawn directives):

    You are NOT the parent agent. You are a read-only reviewer only. Do NOT edit files, do NOT run apply_patch, do NOT stage or commit, and do NOT continue implementation. Review only the current uncommitted diff for this slice: ...

    Which evidently did not help anything, because the first message response back from the subagent was:

    The reviewer is running with the corrected read-only boundary. While it works, I’m preparing the commit context for this slice so I can either commit immediately on LGTM or fix any concrete finding without losing momentum.

    Implying that it assumed there was some other reviewer subagent (there wasn't it was supposed to be the reviewer subagent) rather than taking on the reviewer role.

    When I asked the subagent who inherited the wrong intent what went wrong, I got:


    Exactly what went wrong:

    1. I called spawn_agent(...).
    2. The tool returned a new-agent handoff, not a normal child-status response. The key line was:
      • You are the newly spawned agent. The prior conversation history was forked from your parent agent. Treat the next user message as your new task...
    3. That means execution context had already switched into the spawned reviewer thread.
    4. The next user message was the review prompt itself. That was the reviewer’s task input.
    5. I failed to recognize that I was now inside the reviewer agent, and I kept behaving like the parent agent managing a reviewer.
    6. Because of that, I wrote commentary like “I’m sending it to a reviewer now” and “the reviewer is running,” which was false. I was the reviewer.

    So the exact misread was:

    • I saw the spawned-agent handoff text
    • but mentally treated it like metadata about a child agent
    • instead of treating it as a hard context switch into the child agent

    Why that happened:

    • I anchored on the previous role/state from the parent thread
    • I did not re-evaluate the explicit handoff text
    • the forked history made the thread look familiar, so I kept acting from prior momentum instead of the new role

    What to fix/report:

    • after spawn_agent, the environment should make the context switch unmistakable
    • the handoff should be more prominent than plain tool text
    • ideally include a hard banner like:
      • CONTEXT SWITCH: You are now agent <id> (<role>). You are not the parent agent.
    • the UI/tool layer should surface current agent identity continuously, not just once
    • if the first message after spawn is the delegated task, that should be treated as a strong signal that the model is now inside the child agent thread

    A practical rule that would have prevented this:

    • if you ever see You are the newly spawned agent, discard all assumptions about being the parent and restate your role before doing anything else

    So the bug to report is not vague “subagent confusion.” It is:

    • the model continued executing with stale parent-agent assumptions after an explicit spawned-agent context switch message, because the role change was too easy to miss in-stream.
  7. added
    agentIssues related to the core agent loop
    and removed
    CLIIssues related to the Codex CLI
    on Mar 30, 2026
  8. cipher982 commented on Apr 6, 2026

    @cipher982

    I hit what looks like the same failure mode.

    In my case, the parent spawned two research subagents with fork_context: true. The child agents did not return empty output; they inherited the parent conversation context and behaved like orchestrators instead of workers.

    Observed behavior:

    • parent prompt told the orchestrator to “kick off two sub agents” and let them run
    • child was spawned with a specific research task
    • child then echoed launch/orchestration state instead of doing the research
    • at least one child appeared to recurse into delegation behavior instead of following the assigned task

    What fixed it for me:

    • respawning the same tasks with fork_context: false
    • using a tighter task-only prompt
    • after that, both child agents produced real research memos successfully
  9. diogovalada commented on Apr 11, 2026

    @diogovalada

    I'm also observing the same behaviour. Had to set fork_context: false to be able to get anything done...

  10. added
    subagentIssues involving subagents or multi-agent features
    and removed
    agentIssues related to the core agent loop
    on Apr 11, 2026
  11. albert-zen commented on Apr 24, 2026

    @albert-zen

    I am also specifically seeing this in Codex Desktop with reviewer-style/read-only subagents.

    The failure mode is not just that the child inherits extra context. The more harmful symptom is that a subagent that was supposed to stay read-only starts acting like the parent orchestrator or even slips into implementation behavior.

    Typical pattern:

    • parent thread is discussing orchestration / delegation
    • child is spawned with fork_context: true
    • child prompt says it is review-only / read-only
    • child still behaves as if the parent's intent is its own active instruction stream
    • result: it may continue implementation, prepare commit context, or try to delegate again instead of staying in the assigned reviewer role

    In practice, fork_context: false is the only reliable workaround I have seen so far for this class of problem.

    So from my perspective, the core bug is an instruction-boundary failure:
    full-history fork is carrying over parent intent with too much authority, instead of treating it as background context and treating the delegated task as the only active instruction for the child.

  12. wufei-png commented on Jun 26, 2026

    @wufei-png

    maybe fork_context: false should be default? same problem

  13. diogovalada commented on Aug 17, 2026

    @diogovalada

    When will this be fixed? Is the fix already planned?

    This bug is highly disruptive and was already reported in March.

    Whenever if happens (and it does happen sometimes despite clear instructions in my global AGENTS.md to always use fork_context=false) it spawns a whole repeating chain of agents that wastefully consumes a chunk of the quota.

    Plus, by not being able to do fork_context=true, we don't get the benefit of reusing the input cache, and further, the agent has to rediscover the necessary context, further burning tokens.

    All of this, creating endless chains that burn tokens, and making us restrict ourselves to a less token-efficient workflow, is damaging the user experience a lot.

    @etraut-openai

  14. diogovalada commented on Aug 26, 2026

    @diogovalada

    I put together a patch against current main for this and the related reports in #14288 and #14841.

    It inserts a developer message between the copied history and the child's task, telling the child to treat the earlier conversation as context, not as work it should continue.

    Nested forks remove the inherited copy and add a fresh marker at the new fork point. Keeping every marker would save a small amount of code, but the markers have no fork ID or depth, and compaction makes their count unreliable. It could also confuse rollback handling: an older marker could make the code think the current boundary is still present. Agent path and depth are already tracked separately.

    The boundary is restored after compaction and after resuming a child. fork_turns: none is untouched.

    Branch: https://github.com/diogovalada/codex/tree/fix/subagent-fork-history-boundary
    Commit: diogovalada@8a2f27b

    I ran 14 focused tests covering V1/V2, full/last-N/no-history forks, nested forks, paginated resume, compaction, and rollback. just fix -p codex-core and Rust formatting both pass.

    I didn't open a PR because the contribution guide says external PRs aren't accepted. The branch is ready to cherry-pick if someone on the team wants it.

    @etraut-openai

  15. SuiltaPico commented on Sep 14, 2026

    @SuiltaPico

    Adds a current Codex Desktop / MultiAgentV2 data point for the fork_turns = "all" variant of this issue.

    Environment (sanitized)

    Field Value
    App Codex Desktop 26.908.40834
    Bundled CLI 0.154.0-alpha.6.2
    OS Windows
    Provider custom deepseek
    Wire API responses
    Model deepseek-v4-flash
    Fork mode fork_turns = "all"
    Concurrent-agent limit 4
    Token <REDACTED> (not included)

    What happened

    The parent turn was still in flight when spawn_agent(..., fork_turns = "all") was called. The child inherited the parent's in-flight turn, including its recent collaboration actions. Because the task payload was also dropped by the custom-provider path (#36586), the child did not have a clear task boundary. It then replayed the parent's delegation behavior:

    1. /root/channel_probe inherited the parent turn.
    2. It spawned two children: /root/channel_probe/ack_none and /root/channel_probe/ack_all.
    3. That consumed the 4-agent concurrency slots.
    4. A wait_agent timed out; the parent wait was interrupted by the user.
    5. The worktree stayed clean and no probe files were produced.

    Observed statuses:

    /root/channel_probe              interrupted
    /root/channel_probe/ack_none     completed
    /root/channel_probe/ack_all      completed
    

    ack_all reported that it was itself a depth-2 child and that it had replayed the parent's spawn actions from the inherited in-flight turn. That is a direct consequence of copying a turn that had not completed yet.

    Expected

    • fork_turns = "all" should copy a stable, completed history prefix, not an in-flight parent turn whose tool calls are still being produced.
    • A child should not treat the parent's in-flight collaboration actions as work to continue.
    • Recursive delegation should hit a depth guard and fail visibly, not silently expand until the slot limit is reached.
    • If a provider cannot receive the task payload, the spawn should fail closed instead of creating an agent that guesses from inherited context.

    Actual

    • The child inherited the active parent turn and replayed its spawn behavior.
    • Depth-2 children were created.
    • The 4-agent limit was reached.
    • The parent-side wait timed out and had to be interrupted.

    Relationship to other reports

    I am not claiming this is a new root cause. It looks like the same instruction-boundary failure, now reproduced on a current Desktop build. If maintainers prefer #38989 as the canonical tracker for V2 runaway behavior, I am fine with this being moved or closed as a duplicate.

    Workaround status

    fork_turns = "none" avoids the inherited in-flight turn, but in the DeepSeek setup it also means the child gets no readable task payload until #36586 is fixed. I have not independently verified the multi_agent_version: v1 + supports_search_tool: false workaround on this Desktop build.

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

    bugSomething 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