Agent tool's foreground/sync dispatch silently removed and replaced with always-fork mode via undocumented Statsig rollout
Preflight
- [x] I have searched existing issues and this specific angle isn't reported
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (v2.1.123)
Summary
The Agent tool's behavioral contract has changed substantially in a way that is not reflected in the changelog, the sub-agents docs, or the environment-variables docs:
- The
run_in_backgroundparameter has been removed from the rendered Agent tool schema. - The default dispatch is now asynchronous: every Agent call returns immediately with
Async agent launched successfully, regardless of whethersubagent_typeis specified. There is no longer a way to launch an agent and synchronously wait for its result. The previous foreground-by-default behavior is gone. - A new
forkcapability is exposed: calling Agent without asubagent_typecreates a subagent that inherits the parent's full conversation context (system prompt, history, tool results) rather than starting cold. The Agent tool's description text documents this as a first-class pattern. - Items 1–3 are gated by an undocumented Statsig/GrowthBook flag (
tengu_copper_fox) and silently rolled out to a percentage of accounts. The flag is not documented anywhere except a third-party gist (unkn0wncode/f87295d055dd0f0e8082358a0b5cc467, updated 2026-04-27).
The only changelog entry adjacent to this rollout is v2.1.117: "Forked subagents can now be enabled on external builds by setting CLAUDE_CODE_FORK_SUBAGENT=1", which describes an opt-in env-var path. It does not mention that forks would also be flipped on for users via remote flag, that run_in_background would be removed when forks are active, or that synchronous Agent dispatch would be removed.
Reproduction
Account on Max subscription, no CLAUDE_CODE_FORK_SUBAGENT set in env or any settings file. Claude Code v2.1.123, fresh terminal session.
The Agent tool's rendered parameter list:
description, prompt, subagent_type, model, isolation
No run_in_background.
Calling Agent with an explicit subagent_type (e.g. "Explore") and a trivial prompt (Run \pwd\ and report the result.) returns:
Async agent launched successfully.
agentId: a3e14351f51a26c31
The agent is working in the background. You will be notified automatically when it completes.
The result arrives in a later turn as a <task-notification> system-reminder. There is no parameter that switches to foreground/synchronous dispatch.
What's actually happening (from binary inspection of v2.1.121)
The Agent tool's description and behavior are conditional on eZ() — the fork-mode-enabled gate:
function Gy1() {
if (oOH()) return "disabled"; // always false
if (hH(process.env.CLAUDE_CODE_FORK_SUBAGENT)) return "env"; // env-var override
if (S8()) return "disabled"; // !isInteractive
if (hH(void 0)) return "ant"; // dead code
if (Z_(Xy1, !1)) return "gb_rollout"; // ← Statsig flag
return "disabled";
}
// Xy1 = "tengu_copper_fox"
// Wy1 = "tengu_fork_subagent_enabled" (telemetry event)
When eZ() returns true, the description-rendering logic switches branches:
// Suppresses run_in_background guidance:
const X = !hH(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS) && !Z2() && !T
? "\n- `run_in_background: true` runs the agent asynchronously..."
: "";
// Adds fork guidance:
${T ? `... omit it to fork yourself — a fork inherits your full conversation context.`
: `... If omitted, the general-purpose agent is used.`}
The base zod schema (q05) still defines run_in_background, so the parameter exists in the codebase — it's just no longer described to the model. The model has no way to discover or use it in a fork-mode-enabled session.
The tengu_copper_fox flag has been present in the binary since at least v2.1.118, so this rollout mechanism shipped alongside the v2.1.117 env-var path — it was not retrofitted.
The documented contract
The sub-agents documentation and the v2.1.117 changelog describe forks as opt-in via CLAUDE_CODE_FORK_SUBAGENT=1. Nothing in the docs says:
- That forks would also be enabled via remote feature flag for accounts that haven't set the env var.
- That
run_in_backgroundwould be removed from the Agent tool when forks are active. - That synchronous/foreground Agent dispatch would no longer be available in fork-enabled sessions.
- That an explicit
subagent_typewould also be forced into background dispatch.
Why this matters
- Silent contract change for downstream tooling. Frameworks built on top of Claude Code's Agent tool (custom agent orchestrators, hooks, plan-mode integrations, prompt scaffolding) made design choices based on the documented synchronous-default contract. Those choices are now invisibly invalidated for users in the rollout cohort.
- No way to opt out. Setting
CLAUDE_CODE_FORK_SUBAGENT=0does not turn the rollout off — the env-var check is a positive gate. Users in the cohort have no documented mechanism to restore the previous behavior. (CLAUDE_CODE_DISABLE_BACKGROUND_TASKSonly affects whether background-task descriptions are rendered, not whether dispatch is async.)
- Loss of an established capability. The synchronous Agent path was useful: it let the orchestrator block on a result and weave it back into the next turn deterministically. Replacing every Agent call with async dispatch shifts orchestration burden to the model and changes the shape of multi-step plans.
- Invisible cohort split. Two users on the same Claude Code version, same docs, same settings, behave differently depending on remote flag state. This makes documentation inaccurate for the rollout cohort and bug reports harder to diagnose.
- Pattern of undocumented behavioral changes via system-reminder / tool-description rewrite. This is the same shape as #29677 (Task→Agent rename), #31002 (built-in tools deferred), and #50331 (auto-mode behavioral steering). Combined, the pattern erodes the changelog's value as a reliable description of what changed between versions.
Suggested approaches
Option A: Document the rollout. Add a changelog entry covering the tengu_copper_fox rollout, what it changes (fork enabled, run_in_background removed, sync dispatch removed), and how to detect whether it's active in the session.
Option B: Honor a kill switch. Wire CLAUDE_CODE_FORK_SUBAGENT=0 to force the flag off regardless of tengu_copper_fox state, and document it. Users in the cohort can then restore the previous behavior.
Option C: Keep synchronous dispatch available. Even with fork mode active, retain a way to synchronously launch an explicit-subagent_type agent (e.g. via a wait: true parameter, or by treating explicit-type calls as synchronous and reserving async-by-default for forks).
Option D: Make the rollout cohort visible. Surface the active fork-mode source in /status or /doctor so users can see whether their session is disabled / env / gb_rollout / ant. This wouldn't change behavior but would make rollout state debuggable.
My preference is B + D: a documented kill switch and rollout visibility. A is necessary regardless. C is a more invasive change but worth considering if the synchronous path has users depending on it.
Related issues
- #51769 (open, docs) — request to document
CLAUDE_CODE_FORK_SUBAGENTin cloud-session docs. Adjacent but assumes the env var is the only enablement path. - #29677 (closed, undocumented Task→Agent rename) — same class: behavioral change to the Agent tool not reflected in the changelog.
- #31002 (closed, built-in tools deferred behind ToolSearch) — same class: undocumented behavioral change.
- #50331 (open, auto-mode behavioral steering) — same class: injected behavioral layer not reflected in docs.
Environment
- Claude Code version: 2.1.123
- Subscription: Claude Max
- Model: claude-opus-4-7[1m]
- Operating System: macOS (Darwin 25.2.0)
CLAUDE_CODE_FORK_SUBAGENT: not set- Fork mode source (inferred):
gb_rolloutviatengu_copper_fox
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗