Skip to content

Multi-agent V2 regression: resumed root sessions cannot resume existing subagents #33002

Closed

Description

@hoganfan

Codex version

codex-cli 0.144.3

Variant

Codex CLI with Multi-agent V2

Platform

macOS, arm64

Summary

After a root session is resumed in a new CLI process, Multi-agent V2 cannot resume or route a follow-up to a subagent created by the previous process.

The root conversation history is restored, including the recorded child identifier, but the live agent tree is not. V2 has no equivalent of the V1 resume_agent(id) operation, and followup_task cannot resolve the historical child by either its UUID or canonical task path.

This is a behavioral regression from Multi-agent V1, where a resumed root can explicitly resume a completed child by ID and continue that same child conversation.

Minimal reproduction

With Multi-agent V2 enabled:

  1. Start root process A.
  2. Spawn one child and ask it to remember a distinctive sentinel.
  3. Wait for the child to complete and record its UUID and canonical task path.
  4. Exit process A completely.
  5. Start process B with codex exec resume <root-session-id>.
  6. Ask the resumed root to continue the historical child using followup_task.

Observed results:

  • targeting the UUID returns an agent with id ... not found error;
  • targeting the canonical task path returns a live agent path ... not found error;
  • the root history resumes, but the child cannot be resumed;
  • the only practical fallback is spawning a new child and losing the previous child context.

V1 control experiment

I repeated the same cross-process experiment with codex-cli 0.142.5 and Multi-agent V1:

  1. Process A spawned one child with fork_context=false.
  2. The child memorized a sentinel, returned it, and completed.
  3. Process A exited without closing the child.
  4. Process B resumed the same root session.
  5. The resumed root called resume_agent(child_id), which returned pending_init.
  6. It then called send_input(child_id) with a message that did not contain the sentinel.
  7. The same child returned the sentinel from its first-turn context.
  8. The resumed root made zero spawn_agent calls.

The child rollout retained the same session ID and contained both turns, confirming actual child-session reuse rather than reconstruction by the root.

Expected behavior

Resuming a root session should preserve the ability to continue its existing subagents. Multi-agent V2 could satisfy this by either:

  • rehydrating the persisted agent tree when the root resumes; or
  • providing an explicit resume_agent-style operation that accepts a persisted child thread ID and reconnects it before send_message / followup_task.

If persistent child resumption is intentionally unsupported in V2, this should be documented as an incompatibility and exposed through a deterministic capability/status result so orchestrators can safely fall back.

Why this matters

Long-running orchestrators commonly resume the root session across phases or process restarts. Without child resumption, they cannot continue a specialized review or implementation worker with its accumulated context, even when they persist the exact child ID. This causes avoidable context loss, repeated work, and additional token usage.

Related issues

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    subagentIssues involving subagents or multi-agent features
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    execIssues related to the `codex exec` subcommand
    on Jul 14, 2026
  2. Lansongxxxx commented on Jul 15, 2026

    @Lansongxxxx

    I have an additional Codex Desktop reproduction that narrows the trigger for this issue. It does not require exiting or restarting the app-server process.

    Environment

    • Codex Desktop with bundled codex-cli 0.144.2
    • macOS, arm64
    • Multi-agent V2
    • Root task had several completed subagents with canonical paths

    Desktop reproduction

    1. Spawn several V2 subagents from a root task and let them complete.
    2. Navigate through enough other Desktop tasks for the original root to become an inactive owner subscription.
    3. Desktop calls thread/unsubscribe for the root and marks it needs_resume.
    4. Reopen the root task less than one minute later.
    5. Desktop calls thread/resume; the request carries the current permission profile.
    6. Attempt followup_task with a previously valid canonical path.

    Observed:

    live agent path `/root/<task_name>` not found
    

    The root history resumes successfully, and persisted child identifiers remain visible in reconstructed context, but the new root control plane cannot resolve the old canonical paths. Spawning a new same-named child works, but that is not child-session reuse.

    In the captured timeline, only about 46 seconds elapsed between thread/unsubscribe and thread/resume, so the normal 30-minute no-subscriber idle unload delay cannot explain it.

    Likely immediate trigger

    Current app-server code appears to create an avoidable cold replacement:

    • collect_resume_override_mismatches treats any non-null ThreadResumeParams.permissions as a mismatch, even when the requested permission profile is semantically identical to the loaded thread's active profile.
    • In resume_running_thread, when the loaded root is idle, not running, and has no subscribers, any mismatch causes the existing CodexThread to be shut down and removed immediately.
    • The request then falls through to cold resume, which creates a fresh AgentControl / AgentRegistry.

    The Desktop logs for this reproduction show:

    thread/unsubscribe -> success
    resumeState=needs_resume
    thread/resume -> success
    latestTurnStatus=completed
    shouldSendPermissions=true
    requestPermissionProfile=<same profile as the task>
    

    This means Desktop task subscription eviction plus an equivalent permissions override can turn a routine UI navigation into the same V2 child-resume failure described here.

    Additional V2 recovery gap

    The V2 message path currently resolves the target before attempting lazy reload:

    resolve_agent_reference(path)
    -> ensure_agent_known(thread_id)
    -> ensure_v2_agent_loaded(thread_id)
    

    resolve_agent_reference only checks the in-memory AgentRegistry. After the root control plane is replaced, it returns live agent path ... not found, so ensure_v2_agent_loaded is never reached even though the child rollout and stored agent_path still exist.

    Suggested acceptance criteria

    1. Semantically identical permission overrides must not force replacement of an idle loaded root.
    2. On an in-memory path miss, V2 should resolve persisted open spawn edges / stored agent_path metadata, re-register the child, and then call ensure_v2_agent_loaded.
    3. A resumed root should be able to continue the same child thread ID and history without spawning a replacement.
    4. Add an integration test covering:
      thread/unsubscribe -> thread/resume(with equivalent permissions) -> followup_task(existing canonical path).

    This Desktop-specific path makes the issue much easier to reproduce because it can occur during ordinary task switching without an app restart.

  3. SaravananJaichandar commented on Jul 20, 2026

    @SaravananJaichandar

    Ran into something adjacent last week. Moving subagent state out of the runtime and into an external memory store helped, since the resumed root could rehydrate from the shared store rather than depend on the CLI still knowing about children. Doing this via world-model-mcp. Not a fix for the regression but might unblock the workflow while it gets sorted.

  4. hoganfan commented on Jul 27, 2026

    @hoganfan
    Author

    Confirmed fixed in codex-cli 0.145.0 with Multi-agent V2.

    The matching fix is #32837 (Restore V2 agent identities on root thread resume, commit 088239294a5f). The earliest published prerelease containing that commit is 0.145.0-alpha.8; 0.145.0 is the first stable release containing it. The 0.144.x patch releases do not contain the fix.

    I repeated the original cross-process reproduction on macOS arm64 with 0.145.0:

    1. Process A spawned a V2 child with fork_turns="none", waited for it to complete, and exited.
    2. Process B resumed the same root with codex exec resume <root-session-id>.
    3. The resumed root called followup_task using the child canonical path.
    4. The call succeeded without any replacement spawn_agent; the original child thread received a second turn and retained its own prior context.

    I also repeated the control with fork_turns="all"; both variants succeeded. This confirms that restored child routing is independent of parent-context inheritance.

    Closing as fixed in 0.145.0. Thanks!

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

    CLIIssues related to the Codex CLIbugSomething isn't workingexecIssues related to the `codex exec` subcommandsessionIssues involving session (thread) management, resuming, forking, naming, archivingsubagentIssues 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