What would you like to be added?
Promote the fork subagent from an env-gated experiment to an always-available feature, and give it (plus a built-in autonomous-execution agent) approvalMode: bubble by default, so background work is usable out of the box without hand-written agent definitions.
Three related changes, in increasing order of discussion needed:
1. Remove the QWEN_CODE_ENABLE_FORK_SUBAGENT gate (fork always on in interactive sessions).
Today Config.isForkSubagentEnabled() requires the env var (or programmatic opt-in), and the wrapper in packages/core/src/tools/agent/fork-subagent.ts additionally requires isInteractive(). The proposal is to drop the env-var condition and keep the interactive requirement — non-interactive sessions (-p, SDK headless, CI) continue to fall back to a fresh general-purpose agent, for the reasons already documented in that wrapper's comment (no UI for progress display or permission bubble-up).
Note this is a default-semantics change: with fork enabled, an agent tool call that omits subagent_type becomes a full-context fork instead of a fresh general-purpose agent. That flip is the main thing to weigh (prompt-cache reuse makes forks cheap, but "spawn a clean agent" stops being the no-arg default). /fork and the /btw f shortcut stop requiring setup, and the mustTranslateKeys error string about the gate goes away.
2. Give the fork agent approvalMode: bubble by default.
#4928 / #4955 added permission bubbling for background subagents, opt-in per agent definition. FORK_AGENT (fork-subagent.ts) doesn't carry the mode, so forks still auto-deny any confirmation-requiring tool call — ironic, given the fork gate's own comment cites "permission bubble-up" as why forks need interactive sessions. A fork inherits the full conversation and runs in the background; when it hits a git push-class call, parking the prompt in the Background tasks UI is strictly better than denying and bouncing the work back to the parent turn. One-line change (permissionMode-equivalent on the built-in def) now that the bubbling machinery exists.
3. (Discussion) A built-in bubbling agent for explicit background work — or none of the built-ins bubble.
With #4955, bubbling exists but no built-in agent uses it: a user who says "run this in a background subagent" gets general-purpose, which auto-denies. Options, roughly:
- add a built-in
worker-style agent (tools *, approvalMode: bubble, intended for autonomous background execution) that the model is steered to pick for backgrounded tasks;
- or give
general-purpose itself bubble (broadest reach, but changes behavior for every existing background launch);
- or leave built-ins alone and rely on docs + user-defined agents.
The first option keeps general-purpose's semantics untouched while making bubbling reachable without any user setup.
Why is this needed?
The fork gate has been in place long enough for the feature to stabilize (recursion guard, cache-safe params, transcript bootstrap, resume support all landed), and keeping it env-gated means the /fork command ships disabled for every user who hasn't found the env var. Meanwhile the bubbling work in #4955 fixed the deny-and-bounce failure mode only for users who write their own agent definitions — out of the box, both fork and general-purpose background runs still silently auto-deny and the parent re-runs the command in the foreground, which is the exact UX #4928 was filed about. Wiring the default agents to the new mechanism is the remaining step to make background work usable end to end.
Additional context
What would you like to be added?
Promote the fork subagent from an env-gated experiment to an always-available feature, and give it (plus a built-in autonomous-execution agent)
approvalMode: bubbleby default, so background work is usable out of the box without hand-written agent definitions.Three related changes, in increasing order of discussion needed:
1. Remove the
QWEN_CODE_ENABLE_FORK_SUBAGENTgate (fork always on in interactive sessions).Today
Config.isForkSubagentEnabled()requires the env var (or programmatic opt-in), and the wrapper inpackages/core/src/tools/agent/fork-subagent.tsadditionally requiresisInteractive(). The proposal is to drop the env-var condition and keep the interactive requirement — non-interactive sessions (-p, SDK headless, CI) continue to fall back to a freshgeneral-purposeagent, for the reasons already documented in that wrapper's comment (no UI for progress display or permission bubble-up).Note this is a default-semantics change: with fork enabled, an
agenttool call that omitssubagent_typebecomes a full-context fork instead of a freshgeneral-purposeagent. That flip is the main thing to weigh (prompt-cache reuse makes forks cheap, but "spawn a clean agent" stops being the no-arg default)./forkand the/btwfshortcut stop requiring setup, and themustTranslateKeyserror string about the gate goes away.2. Give the fork agent
approvalMode: bubbleby default.#4928 / #4955 added permission bubbling for background subagents, opt-in per agent definition.
FORK_AGENT(fork-subagent.ts) doesn't carry the mode, so forks still auto-deny any confirmation-requiring tool call — ironic, given the fork gate's own comment cites "permission bubble-up" as why forks need interactive sessions. A fork inherits the full conversation and runs in the background; when it hits agit push-class call, parking the prompt in the Background tasks UI is strictly better than denying and bouncing the work back to the parent turn. One-line change (permissionMode-equivalent on the built-in def) now that the bubbling machinery exists.3. (Discussion) A built-in bubbling agent for explicit background work — or none of the built-ins bubble.
With #4955, bubbling exists but no built-in agent uses it: a user who says "run this in a background subagent" gets
general-purpose, which auto-denies. Options, roughly:worker-style agent (tools*,approvalMode: bubble, intended for autonomous background execution) that the model is steered to pick for backgrounded tasks;general-purposeitselfbubble(broadest reach, but changes behavior for every existing background launch);The first option keeps
general-purpose's semantics untouched while making bubbling reachable without any user setup.Why is this needed?
The fork gate has been in place long enough for the feature to stabilize (recursion guard, cache-safe params, transcript bootstrap, resume support all landed), and keeping it env-gated means the
/forkcommand ships disabled for every user who hasn't found the env var. Meanwhile the bubbling work in #4955 fixed the deny-and-bounce failure mode only for users who write their own agent definitions — out of the box, both fork andgeneral-purposebackground runs still silently auto-deny and the parent re-runs the command in the foreground, which is the exact UX #4928 was filed about. Wiring the default agents to the new mechanism is the remaining step to make background work usable end to end.Additional context
FORK_AGENT+ i18n/string cleanup + test updates); item 3 needs a short design decision first.isInteractive()requirement should stay for fork regardless — nothing here proposes enabling fork in headless contexts.