Skip to content

[Critical UX regression] multi-agent v2 spawn_agent hides model overrides and rejects the default call shape #32031

Open

Description

@lidge-jun

Summary

On the multi-agent v2 surface (the default for gpt-5.6-sol / gpt-5.6-terra, and for any model when features.multi_agent_v2 is enabled), sub-agent model selection is effectively unusable: the default schema makes it undiscoverable, and the natural override call fails. The runtime fully supports the override — but agents on the default surface see no model property, conclude the capability does not exist, and tell users so. This is a severe UX regression from v1, where the spawn tool advertised up to 5 picker-visible models and fresh spawns with model overrides just worked.

Filing as an issue with a patch branch attached because PRs to this repo are staff-only.

What the user sees

User: "spawn a gpt-5.6-terra sub-agent for this"
Agent: "The current spawn_agent interface has no model selection argument, so I cannot spawn a sub-agent on gpt-5.6-terra."

The agent is wrong — SpawnAgentArgs parses and applies model / reasoning_effort regardless of schema visibility — but it has no way to know that, because the schema it sees does not contain those properties. Observed repeatedly with gpt-5.6-sol under ChatGPT auth, codex-cli 0.143.0 / Codex Desktop, main @ 1f0566d3f (2026-07-10).

Root cause: two compounding defaults

  1. hide_spawn_agent_metadata defaults to true (core/src/config/mod.rs). The v2 spawn_agent schema strips model, reasoning_effort, agent_type, and service_tier, and drops the v1-style "Available model overrides" description listing up to 5 picker-visible models (hide_spawn_agent_metadata_options, core/src/tools/handlers/multi_agents_spec.rs).
  2. Omitted fork_turns defaults to a full-history fork, which rejects overrides (core/src/tools/handlers/multi_agents_v2/spawn.rs + reject_full_fork_spawn_overrides). So even when the model is told the arguments exist, the natural call — overrides without an explicit fork_turns — errors with Full-history forked agents inherit the parent agent type, model, and reasoning effort; .... The override only works with fork_turns: "none" or a partial fork, which nothing on the default surface teaches.

Each default is defensible alone; together they make a supported capability undiscoverable AND broken in its natural call shape. Users relying on the default surface can hit both walls before ever learning the explicit-fork workaround exists.

The config escape hatch does not work under ChatGPT auth

Setting [features.multi_agent_v2] hide_spawn_agent_metadata = false locally is not a workaround for ChatGPT-auth users: in our testing (ChatGPT auth, gpt-5.6-sol, 2026-07-10) the backend treats collaboration.spawn_agent as a reserved function and rejects every request whose declared schema deviates:

Invalid Value: 'tools'. Function 'collaboration.spawn_agent' is reserved for use by this model and must match the configured schema.

So for this configuration the hidden schema is the only accepted one, and the only working path is undocumented prompt knowledge. A client-side default flip therefore requires a coordinated update to the backend's reserved-function schema — which is exactly why this needs to be fixed here rather than worked around downstream.

Reproduction

  1. codex with a v2-surface model (e.g. gpt-5.6-sol, ChatGPT auth, all defaults).
  2. Ask: "spawn a sub-agent on gpt-5.6-terra".
  3. Observe the agent either (a) claim model selection is unsupported, or (b) attempt spawn_agent {model: "gpt-5.6-terra"} without fork_turns and receive the full-history-fork rejection.
  4. Optionally set hide_spawn_agent_metadata = false and observe the reserved-schema rejection above on every turn.

Proposed fix (patch branch attached)

Branch: https://github.com/lidge-jun/codex/tree/codex/spawn-agent-metadata-ux (single commit fde7de4d0; happy to iterate)

  1. Default hide_spawn_agent_metadata to false — restore v1 parity: the schema advertises the override arguments and up to 5 picker-visible models. The slim schema stays available as an explicit opt-in. Note: this also surfaces the spawned agent's nickname in results (SpawnAgentResult::WithNickname), and needs the coordinated backend schema update noted above for ChatGPT-auth configurations.
  2. When fork_turns is truly omitted and an override (agent_type/model/reasoning_effort) is present, treat the spawn as fresh (fork_turns: "none") instead of erroring — unstated fork intent plus explicit override intent means a fresh specialist spawn, matching v1 semantics. Explicit input keeps its meaning: fork_turns: "all" (and blank strings) still keep the full-history default and reject overrides, preserving the inherit-everything contract.

Tests: overrides-with-omitted-fork_turns fresh-spawn behavior, explicit-all agent_type-only rejection, blank-fork_turns rejection, surfaced nickname expectations. cargo test -p codex-core --lib multi_agents: 89 passed / config::: 439 passed / integration spawn_agent filter: 7 passed. Pre-existing failure unrelated to this patch: multi_agent_v2_completion_ignores_dead_direct_parent stack-overflows on a clean checkout of main @ 1f0566d3f.

Why this deserves priority

This is a capability regression with active user-facing misinformation: the agent confidently tells users a shipped capability does not exist, and the failure mode (agent denial) means most users will never learn the capability is there at all. The fix is small, v1-parity-restoring, and covered by tests — the main coordination cost is the backend schema update, which only this repo's owners can drive.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    appIssues related to the Codex desktop app
    subagentIssues involving subagents or multi-agent features
    configIssues involving config.toml, config keys, config merging, or config updates
    on Jul 10, 2026
  2. github-actions commented on Jul 10, 2026

    @github-actions
    Contributor
  3. lidge-jun commented on Jul 10, 2026

    @lidge-jun
    Author

    Reviewed both candidates — they are related but this issue is not a pure duplicate of either. To make triage easy:

    Overlap:

    What this issue adds that neither covers:

    1. The second, compounding default: even when the override arguments ARE passed (e.g. via prompt guidance), the natural call shape — overrides without an explicit fork_turns — still fails, because omitted fork_turns defaults to a full-history fork and reject_full_fork_spawn_overrides rejects it. Fixing the schema visibility alone (GPT-5.6 Sol cannot specify subagent models, forcing all subagents to also be Sol instances #31814's ask) leaves this second wall in place: the model must also know to pass fork_turns: "none", which nothing on the surface teaches.
    2. A tested patch for both defaults: https://github.com/lidge-jun/codex/tree/codex/spawn-agent-metadata-ux — flips the default AND makes truly-omitted fork_turns + override fall back to a fresh spawn (explicit "all" still rejects, preserving the inherit contract). 89 targeted multi_agents tests pass, including new coverage for the fallback and blank-fork_turns edge cases.
    3. The user-facing failure mode framing: the agent actively tells users the capability does not exist, which is why this reads as a removed feature rather than a config knob.

    Happy to consolidate into #31814 if maintainers prefer one thread — but please carry the fork_turns compounding default over if so, since restoring schema visibility alone does not make the natural call succeed.

  4. hoojunhao commented on Jul 10, 2026

    @hoojunhao

    I can reproduce the visible-schema side of this on Codex Desktop / CLI 0.144.1 (macOS).

    • Global config has a model and model_reasoning_effort configured.
    • A custom agent TOML can also declare model and model_reasoning_effort.
    • However, the spawn_agent tool exposed to this interactive thread accepts only task_name, message, and fork_turns. It exposes no agent_type, model, or reasoning-effort parameter.
    • Therefore there is no discoverable way to select the custom agent or request a per-spawn model/reasoning override. For this surface, the documented TOML fields cannot be intentionally applied to a general spawned subagent; it can only use whatever the orchestrator chooses/inherits.

    Expected: either expose a supported custom-agent selector and/or per-spawn model / model_reasoning_effort fields, or document this surface's limitation and a supported routing mechanism.

    This matters for intentionally routing bounded sub-tasks to a faster/lower-cost model while keeping the parent on a stronger model.

    I am intentionally not including local paths, account information, or full configuration output.

  5. labib-rahman-zocdoc commented on Jul 10, 2026

    @labib-rahman-zocdoc

    Confirming reproduction. This is breaking a lot of the guidance and training we've written for Codex usage in my organization.

  6. Loong0x00 commented on Jul 20, 2026

    @Loong0x00

    Strong +1. This should not require defining a static custom-agent preset for every model × reasoning-effort combination.

    The parent agent should be able to pass ordinary string arguments for each individual spawn:

    {
      "task_name": "implement_small_change",
      "message": "...",
      "fork_turns": "none",
      "model": "gpt-5.6-terra",
      "reasoning_effort": "high"
    }

    That is a basic orchestration primitive: use a strong coordinator, cheaper/faster workers for bounded tasks, and stronger reviewers only where needed. Hiding these parameters and forcing every child to inherit the parent wastes usage and makes adaptive routing impossible.

    Claude Code already supports this.

    Please expose model and reasoning_effort in the stable model-visible spawn_agent schema. If a requested value is unsupported, fail explicitly rather than silently inheriting the parent configuration.

  7. lidge-jun commented on Jul 24, 2026

    @lidge-jun
    Author

    Confirming this is still current on main as of today. codex-rs/core/src/tools/handlers/multi_agents_spec.rs was last touched 2026-07-18 (#33932), so the logic below is what ships right now.

    Fresh file:line evidence (@ f201c30c5):

    1. v2 schema strips the override properties by default — multi_agents_spec.rs:116-119:
      if !options.expose_spawn_agent_model_overrides {
          properties.remove("model");
          properties.remove("reasoning_effort");
      }
    2. The gate is config-only and off by default — core/src/tools/spec_plan.rs:819-822 wires expose_spawn_agent_model_overrides straight from config.multi_agent_v2.expose_spawn_agent_model_overrides (default false). Nothing in the product turns it on, so every default v2 surface hides the capability.
    3. v1 does the opposite, hardcoded — spec_plan.rs:869 sets expose_spawn_agent_model_overrides: true for the v1 tool. This is the exact asymmetry behind the "regression from v1" report.
    4. The runtime still fully supports overrides — core/src/tools/handlers/multi_agents_v2/spawn.rs (SpawnAgentArgs) parses model, reasoning_effort, and service_tier and applies them. The capability exists; only the advertisement is missing.
    5. It fails in both directions — the v2 parameters are built with additionalProperties: false and required: ["task_name", "message"] (multi_agents_spec.rs:137-141). So an agent that trusts the schema concludes "model selection does not exist" and tells the user so, and an agent that attempts the natural override anyway (model: "...", from v1 habit or explicit user instruction) risks a schema-validation rejection. Undiscoverable and punished for trying.

    Why this matters more than a normal feature gap: the tool schema is the model's only source of truth about its own capabilities. Hiding a supported property doesn't just obscure a feature — it manufactures false "I can't do that" answers, which is strictly worse UX than not having the feature.

    Minimal fix proposal: align v2 with v1 — advertise model / reasoning_effort by default (flip the Default for expose_spawn_agent_model_overrides to true, or drop the stripping entirely). The existing multi_agent_v2.expose_spawn_agent_model_overrides config knob can stay as an opt-out for deployments that want to lock sub-agent models. Happy to prepare this as a patch branch on my fork if a maintainer confirms the direction (PRs here are staff-only).

  8. Gerry9000 commented on Jul 29, 2026

    @Gerry9000

    Confirmed on Ubuntu with codex-cli 0.145.0.

    The native collaboration.spawn_agent schema available to the parent advertises explicit model overrides for gpt-5.6-sol and gpt-5.6-terra, but omits gpt-5.6-luna. Agents consequently report that Luna cannot be selected through native spawning.

    As a control, Luna works successfully through the same installed CLI:

    $ codex exec --ephemeral --ignore-rules --sandbox read-only --model gpt-5.6-luna --json "Reply with exactly: LUNA-0145-OK"
    ...
    {"type":"item.completed","item":{"type":"agent_message","text":"LUNA-0145-OK"}}
    {"type":"turn.completed",...}

    So this still reproduces on 0.145.0 as a native subagent schema/model-catalog limitation, not a CLI-version inability to run Luna directly.

  9. Gerry9000 commented on Jul 29, 2026

    @Gerry9000

    Verified working workaround on Ubuntu with codex-cli 0.145.0 and ChatGPT authentication. The immediate rejection is caused by the bundled catalog marking Sol/Terra as MultiAgent V2 while Luna is marked V1; model_supports_multi_agent_backend therefore filters Luna from a V2 parent.

    Create a full catalog override with only Luna changed to V2:

    mkdir -p ~/.codex
    gh api repos/openai/codex/contents/codex-rs/models-manager/models.json \
      -H "Accept: application/vnd.github.raw+json" \
      | jq '(.models[] | select(.slug == "gpt-5.6-luna").multi_agent_version) = "v2"' \\\n  > ~/.codex/model-catalog-luna-v2.json\nchmod 0444 ~/.codex/model-catalog-luna-v2.json\n```\n\nAdd to `~/.codex/config.toml`:\n\n```toml\nmodel_catalog_json = "/home/YOUR_USER/.codex/model-catalog-luna-v2.json"\n\n[features.multi_agent_v2]\nexpose_spawn_agent_model_overrides = true\n```\n\nStart a fresh Codex process, then spawn with an explicit fresh fork:\n\n```json\n{\n  "task_name": "luna_probe",\n  "message": "Reply exactly: GLOBAL-LUNA-NATIVE-OK",\n  "fork_turns": "none",\n  "model": "gpt-5.6-luna",\n  "reasoning_effort": "low"\n}\n```\n\nThis produced a real native child rollout with `source.subagent.thread_spawn.agent_path = "/root/global_luna_probe"`, `turn_context.model = "gpt-5.6-luna"`, `turn_context.effort = "low"`, and response `GLOBAL-LUNA-NATIVE-OK`. No custom Codex build was required.\n\nCaveat: `model_catalog_json` replaces the full bundled catalog, so this file should be refreshed when Codex updates and removed once the upstream catalog marks Luna V2.
  10. pbowyer commented on Jul 30, 2026

    @pbowyer

    @Gerry9000's catalog override worked for me, and I've fixed the formatting in their message so you can copy and paste:

    mkdir -p ~/.codex
    gh api repos/openai/codex/contents/codex-rs/models-manager/models.json \
      -H "Accept: application/vnd.github.raw+json" \
    | jq '(.models[] | select(.slug == "gpt-5.6-luna").multi_agent_version) = "v2"' > ~/.codex/model-catalog-luna-v2.json
    chmod 0444 ~/.codex/model-catalog-luna-v2.json
    

    Add to ~/.codex/config.toml:

    model_catalog_json = "/home/YOUR_USER/.codex/model-catalog-luna-v2.json"
    
    [features.multi_agent_v2]
    expose_spawn_agent_model_overrides = true
    

    Caveat: model_catalog_json replaces the full bundled catalog, so this file should be refreshed when Codex updates and removed once the upstream catalog marks Luna V2.

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 CLIappIssues related to the Codex desktop appbugSomething isn't workingconfigIssues involving config.toml, config keys, config merging, or config updatessubagentIssues 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