Add a hard config kill-switch and warning path for spawn_agent fork_context

Open 💬 1 comment Opened Mar 17, 2026 by ignatremizov

What variant of Codex are you using?

v0.115 CLI / TUI (local codex-rs based app-server sessions)

What feature would you like to see?

Add a hard config-level control to disable spawn_agent(..., fork_context=true) entirely, plus a user-facing warning when a forked spawn would snapshot a large parent thread.

Concretely:

  1. Add a config setting that makes fork_context=true unavailable at runtime.
  • Example shape: [agents] allow_fork_context = false or equivalent.
  • When disabled, the spawn_agent handler should reject any call with fork_context=true before thread fork / rollout snapshotting begins.
  • This should be enforceable regardless of model behavior, prompt wording, or role choice.
  1. Add an optional warning / guardrail for expensive forks.
  • Before forking parent history, estimate the amount of context being inherited (turn count / items / serialized bytes / prompt tokens, whichever is most practical).
  • If the inherited snapshot exceeds a threshold, either:
  • emit a strong warning into the tool description / runtime event stream, or
  • require an explicit second opt-in mechanism before allowing the fork.
  1. Add a finer-grained control for built-in collab tools, separate from agents.max_depth.
  • agents.max_depth already limits recursive spawning depth, and at the depth boundary the child loses the collab tool bundle.
  • The remaining gap is earlier than that boundary: fork_context=true can still be chosen on the first child, and intermediate children still retain the full collab surface until they hit max depth.
  • Users may want top-level orchestration while still forbidding some or all built-in collab tools for spawned children before the depth boundary is reached.

Why this matters:

  • In real multi-agent sessions, fork_context=true can snapshot very large parent histories into child agents.
  • In long-lived or resumed threads, that inherited history can include stale prompts, prior orchestration metadata, agent IDs, prior tool outputs, and unrelated old work.
  • This is both a correctness risk and a token-burn amplifier.
  • A soft prompt instruction saying “prefer fork_context=false” is not sufficient because the model can still choose true.

This request is intentionally narrower than earlier issues that asked for the existence of fork_context itself. The parameter exists today, but there is no hard user control to forbid it.

Additional information

Why I think this should be productized instead of left to prompting:

  • In the current spawn path, fork_context is an explicit boolean tool arg, defaulting to false when omitted, but when true it forks the parent thread history into the child before the first task handoff. See local source:
  • codex-rs/core/src/tools/spec.rs
  • codex-rs/core/src/tools/handlers/multi_agents/spawn.rs
  • codex-rs/core/src/agent/control.rs
  • agents.max_depth already limits recursive spawn depth. In the current implementation, once child_depth >= agent_max_depth, the child config has both Feature::SpawnCsv and Feature::Collab disabled, so the collab tool bundle is removed at that depth.
  • The missing control is therefore narrower than “workers at max depth can still spawn.” The real gap is:
  • the first forked child before depth protection matters
  • intermediate children when max depth is greater than 1
  • lack of a user-facing built-in-tool config for selectively disabling core collab tools like spawn_agent / send_input / wait_agent / close_agent
  • From the current code, enabled_tools / disabled_tools config appears to apply to MCP/app tools, not built-in core tools. Built-in collab tools are currently registered as a group when config.collab_tools is enabled.
  • In local rollout JSONL from a real session, child threads created with fork_context=true clearly inherited:
  • parent session_meta
  • old developer/user instructions
  • stale orchestration context from older resumed sessions
  • enough collab history to know about sibling/descendant agent IDs near the tail of inherited context
  • This is consistent with related reports around forked workers inheriting parent directive boundaries or recursively delegating:
  • #12431
  • #13491
  • #14288
  • It may also be one contributor to unusually high token burn in multi-agent workflows reported in:
  • #13568
  • #14750

I do not think this explains every high-usage report. But for the subset involving long-lived multi-agent threads, it looks like a credible and avoidable amplifier.

Proposed implementation plan:

  1. Config/schema
  • Add a boolean config field under agents (or another appropriate top-level section) to allow/deny forked spawns.
  • Default can remain permissive for backward compatibility, but a hard off switch should exist.
  1. Spawn handler enforcement
  • In spawn_agent, reject fork_context=true when the config disallows it.
  • Return a clear model-visible error like: fork_context is disabled by config; spawn a fresh child or update config intentionally.
  1. Runtime warning / estimation
  • Before ensure_rollout_materialized() + fork snapshot, compute a lightweight inherited-context estimate.
  • If above threshold, surface a warning in the collab event stream and optionally in the model-visible tool result.
  1. Built-in collab-tool ergonomics
  • Document and/or provide a built-in worker role preset that disables collab tools for children before the depth boundary.
  • If possible, add a simple role-level or child-agent config toggle so users do not need to understand internal feature wiring.
  1. Tests
  • config parsing + schema coverage
  • spawn rejection when fork_context is disabled
  • warning emission when estimated inherited context exceeds threshold
  • regression coverage to ensure fork_context=false behavior is unchanged

Expected outcome:

  • users who never want forked history can make that impossible
  • users who do allow it get clearer visibility into the cost/risk before triggering it
  • multi-agent worker trees become safer and more predictable

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗