From 5f2f60bed6d573c53ea9806f058d0710c4821776 Mon Sep 17 00:00:00 2001 From: Adib234 <30782825+Adib234@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:52:27 -0500 Subject: [PATCH] feat(plan): enable built-in research subagents in plan mode (#20972) --- docs/cli/plan-mode.md | 15 ++++++---- packages/core/src/policy/policies/plan.toml | 11 ++++++- .../core/src/policy/policy-engine.test.ts | 4 +-- packages/core/src/policy/toml-loader.test.ts | 29 +++++++++++++++---- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/docs/cli/plan-mode.md b/docs/cli/plan-mode.md index dce7e2886e..a8511d9c42 100644 --- a/docs/cli/plan-mode.md +++ b/docs/cli/plan-mode.md @@ -25,7 +25,7 @@ implementation. It allows you to: - [Customizing Planning with Skills](#customizing-planning-with-skills) - [Customizing Policies](#customizing-policies) - [Example: Allow git commands in Plan Mode](#example-allow-git-commands-in-plan-mode) - - [Example: Enable research subagents in Plan Mode](#example-enable-research-subagents-in-plan-mode) + - [Example: Enable custom subagents in Plan Mode](#example-enable-custom-subagents-in-plan-mode) - [Custom Plan Directory and Policies](#custom-plan-directory-and-policies) - [Automatic Model Routing](#automatic-model-routing) - [Cleanup](#cleanup) @@ -134,6 +134,7 @@ These are the only allowed tools: - **FileSystem (Read):** [`read_file`], [`list_directory`], [`glob`] - **Search:** [`grep_search`], [`google_web_search`] +- **Research Subagents:** [`codebase_investigator`], [`cli_help`] - **Interaction:** [`ask_user`] - **MCP Tools (Read):** Read-only [MCP tools] (e.g., `github_read_issue`, `postgres_read_schema`) are allowed. @@ -204,16 +205,17 @@ priority = 100 modes = ["plan"] ``` -#### Example: Enable research subagents in Plan Mode +#### Example: Enable custom subagents in Plan Mode -You can enable experimental research [subagents] like `codebase_investigator` to -help gather architecture details during the planning phase. +Built-in research [subagents] like [`codebase_investigator`] and [`cli_help`] +are enabled by default in Plan Mode. You can enable additional [custom +subagents] by adding a rule to your policy. `~/.gemini/policies/research-subagents.toml` ```toml [[rule]] -toolName = "codebase_investigator" +toolName = "my_custom_subagent" decision = "allow" priority = 100 modes = ["plan"] @@ -319,7 +321,10 @@ those files are not automatically deleted and must be managed manually. [MCP tools]: /docs/tools/mcp-server.md [`save_memory`]: /docs/tools/memory.md [`activate_skill`]: /docs/cli/skills.md +[`codebase_investigator`]: /docs/core/subagents.md#codebase_investigator +[`cli_help`]: /docs/core/subagents.md#cli_help [subagents]: /docs/core/subagents.md +[custom subagents]: /docs/core/subagents.md#creating-custom-subagents [policy engine]: /docs/reference/policy-engine.md [`enter_plan_mode`]: /docs/tools/planning.md#1-enter_plan_mode-enterplanmode [`exit_plan_mode`]: /docs/tools/planning.md#2-exit_plan_mode-exitplanmode diff --git a/packages/core/src/policy/policies/plan.toml b/packages/core/src/policy/policies/plan.toml index 1af21ba9b6..86f6554de5 100644 --- a/packages/core/src/policy/policies/plan.toml +++ b/packages/core/src/policy/policies/plan.toml @@ -72,7 +72,16 @@ priority = 70 modes = ["plan"] [[rule]] -toolName = ["glob", "grep_search", "list_directory", "read_file", "google_web_search", "activate_skill"] +toolName = [ + "glob", + "grep_search", + "list_directory", + "read_file", + "google_web_search", + "activate_skill", + "codebase_investigator", + "cli_help" +] decision = "allow" priority = 70 modes = ["plan"] diff --git a/packages/core/src/policy/policy-engine.test.ts b/packages/core/src/policy/policy-engine.test.ts index 4c9b9cbfcd..b8e6968af9 100644 --- a/packages/core/src/policy/policy-engine.test.ts +++ b/packages/core/src/policy/policy-engine.test.ts @@ -1593,7 +1593,7 @@ describe('PolicyEngine', () => { modes: [ApprovalMode.PLAN], }, { - toolName: 'codebase_investigator', + toolName: 'unknown_subagent', decision: PolicyDecision.ALLOW, priority: PRIORITY_SUBAGENT_TOOL, }, @@ -1605,7 +1605,7 @@ describe('PolicyEngine', () => { }); const fixedResult = await fixedEngine.check( - { name: 'codebase_investigator' }, + { name: 'unknown_subagent' }, undefined, ); diff --git a/packages/core/src/policy/toml-loader.test.ts b/packages/core/src/policy/toml-loader.test.ts index 30236d80c2..a65248cfea 100644 --- a/packages/core/src/policy/toml-loader.test.ts +++ b/packages/core/src/policy/toml-loader.test.ts @@ -909,7 +909,7 @@ priority = 100 } }); - it('should override default subagent rules when in Plan Mode', async () => { + it('should override default subagent rules when in Plan Mode for unknown subagents', async () => { const planTomlPath = path.resolve(__dirname, 'policies', 'plan.toml'); const fileContent = await fs.readFile(planTomlPath, 'utf-8'); const tempPolicyDir = await fs.mkdtemp( @@ -931,9 +931,9 @@ priority = 100 approvalMode: ApprovalMode.PLAN, }); - // 3. Simulate a Subagent being registered (Dynamic Rule) + // 3. Simulate an unknown Subagent being registered (Dynamic Rule) engine.addRule({ - toolName: 'codebase_investigator', + toolName: 'unknown_subagent', decision: PolicyDecision.ALLOW, priority: PRIORITY_SUBAGENT_TOOL, source: 'AgentRegistry (Dynamic)', @@ -942,13 +942,13 @@ priority = 100 // 4. Verify Behavior: // The Plan Mode "Catch-All Deny" (from plan.toml) should override the Subagent Allow const checkResult = await engine.check( - { name: 'codebase_investigator' }, + { name: 'unknown_subagent' }, undefined, ); expect( checkResult.decision, - 'Subagent should be DENIED in Plan Mode', + 'Unknown subagent should be DENIED in Plan Mode', ).toBe(PolicyDecision.DENY); // 5. Verify Explicit Allows still work @@ -958,6 +958,25 @@ priority = 100 readResult.decision, 'Explicitly allowed tools (read_file) should be ALLOWED in Plan Mode', ).toBe(PolicyDecision.ALLOW); + + // 6. Verify Built-in Research Subagents are ALLOWED + const codebaseResult = await engine.check( + { name: 'codebase_investigator' }, + undefined, + ); + expect( + codebaseResult.decision, + 'codebase_investigator should be ALLOWED in Plan Mode', + ).toBe(PolicyDecision.ALLOW); + + const cliHelpResult = await engine.check( + { name: 'cli_help' }, + undefined, + ); + expect( + cliHelpResult.decision, + 'cli_help should be ALLOWED in Plan Mode', + ).toBe(PolicyDecision.ALLOW); } finally { await fs.rm(tempPolicyDir, { recursive: true, force: true }); }