Summary
When a parent task delegates a child in a different mode, two runtime paths read the shared provider mode instead of the task-local mode. The child environment text reports the parent mode. Tool validation receives the parent mode and rejects tools that the child mode allows. The UI, the persisted history item, the system prompt, and the native tool schema all correctly show the child mode. Only these two readers diverge.
Steps to reproduce
- Define a custom mode
review whose groups include a group the parent lacks, for example edit.
- Start a parent task in
orchestrator mode.
- Approve a
new_task delegation to review.
- Ask the child to use a Review-only tool.
- Read the
Current Mode block of the child request.
- The tool call fails with:
Tool "apply_diff" is not allowed in this mode.
Expected behavior
The environment text reports review. Tool validation receives review and allows Review tools.
Actual behavior
The environment text reports orchestrator. Tool validation receives orchestrator and rejects the Review tool.
Root cause
Commit b89962460319ade787888316a5076211dc07aec9 (PR #1494, merged 2026-09-10, first shipped in v3.82.1) removed handleModeSwitch from the delegation flow. Delegation now passes an explicit handoffExecutionContext and stores the mode on the task. Two legacy readers still read the shared provider mode:
src/core/environment/getEnvironmentDetails.ts lines 207 to 225. The function destructures mode from provider state and prints it into the Current Mode block.
src/core/assistant-message/presentAssistantMessage.ts line 346 reads provider state. Line 620 passes that mode to validateToolUse().
Before the regression, delegation switched the shared mode. Both readers stayed correct by accident. git blame confirms the defective lines are inherited and unchanged. The task-local pattern already exists at src/core/task/Task.ts line 816 (getTaskMode()). Request construction and prompt building use it. That is why the tool schema says review while validation says orchestrator.
Regression range
Test gaps
src/core/environment/__tests__/getEnvironmentDetails.spec.ts seeds mode code and never sets a divergent task mode. It pins the current behavior.
src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts mocks validateToolUse and never asserts the mode argument.
- The three suites that own this behavior pass while the defect exists: 3 files, 35 tests, all green.
Suggested fix
- In
getEnvironmentDetails.ts, read the mode through cline.getTaskMode(). Keep custom mode definitions from provider state.
- In
presentAssistantMessage.ts, pass the task-local mode to validateToolUse().
- Add a regression test with provider mode
orchestrator and task mode review. Assert the environment text reports review. Assert validateToolUse receives review. Assert edit tools stay blocked in review mode.
- Follow-up audit of the SkillTool, RunSlashCommandTool, and MCP restriction modules for the same shared-mode read pattern.
Summary
When a parent task delegates a child in a different mode, two runtime paths read the shared provider mode instead of the task-local mode. The child environment text reports the parent mode. Tool validation receives the parent mode and rejects tools that the child mode allows. The UI, the persisted history item, the system prompt, and the native tool schema all correctly show the child mode. Only these two readers diverge.
Steps to reproduce
reviewwhose groups include a group the parent lacks, for exampleedit.orchestratormode.new_taskdelegation toreview.Current Modeblock of the child request.Tool "apply_diff" is not allowed in this mode.Expected behavior
The environment text reports
review. Tool validation receivesreviewand allows Review tools.Actual behavior
The environment text reports
orchestrator. Tool validation receivesorchestratorand rejects the Review tool.Root cause
Commit
b89962460319ade787888316a5076211dc07aec9(PR #1494, merged 2026-09-10, first shipped in v3.82.1) removedhandleModeSwitchfrom the delegation flow. Delegation now passes an explicithandoffExecutionContextand stores the mode on the task. Two legacy readers still read the shared provider mode:src/core/environment/getEnvironmentDetails.tslines 207 to 225. The function destructuresmodefrom provider state and prints it into theCurrent Modeblock.src/core/assistant-message/presentAssistantMessage.tsline 346 reads provider state. Line 620 passes that mode tovalidateToolUse().Before the regression, delegation switched the shared mode. Both readers stayed correct by accident.
git blameconfirms the defective lines are inherited and unchanged. The task-local pattern already exists atsrc/core/task/Task.tsline 816 (getTaskMode()). Request construction and prompt building use it. That is why the tool schema saysreviewwhile validation saysorchestrator.Regression range
14918c8f(2026-08-05, PR fix(task): isolate task configuration from focused provider state #1085): unaffected.b8996246(2026-09-10, PR [Fix] Nested subtask tool calls no longer stall #1494): affected. This commit is the regression.git tag --contains b8996246returnsv3.82.1only.Test gaps
src/core/environment/__tests__/getEnvironmentDetails.spec.tsseeds modecodeand never sets a divergent task mode. It pins the current behavior.src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.tsmocksvalidateToolUseand never asserts the mode argument.Suggested fix
getEnvironmentDetails.ts, read the mode throughcline.getTaskMode(). Keep custom mode definitions from provider state.presentAssistantMessage.ts, pass the task-local mode tovalidateToolUse().orchestratorand task modereview. Assert the environment text reportsreview. AssertvalidateToolUsereceivesreview. Assert edit tools stay blocked inreviewmode.