From 35ee2a841a7ea9e82772232f38b1200c622e02a6 Mon Sep 17 00:00:00 2001 From: Jerop Kipruto Date: Mon, 9 Mar 2026 11:58:46 -0400 Subject: [PATCH] feat(plan): enable Plan Mode by default (#21713) --- docs/cli/plan-mode.md | 25 +++---------------- docs/cli/settings.md | 2 +- docs/reference/commands.md | 4 +-- docs/reference/configuration.md | 4 +-- packages/cli/src/acp/acpClient.test.ts | 4 +-- packages/cli/src/acp/acpResume.test.ts | 7 +++++- packages/cli/src/config/config.test.ts | 4 +-- .../cli/src/config/settingsSchema.test.ts | 6 ++--- packages/cli/src/config/settingsSchema.ts | 4 +-- .../src/services/BuiltinCommandLoader.test.ts | 4 +-- .../cli/src/ui/components/Composer.test.tsx | 2 +- .../ui/hooks/useApprovalModeIndicator.test.ts | 2 +- packages/core/src/config/config.test.ts | 4 +-- packages/core/src/config/config.ts | 2 +- schemas/settings.schema.json | 6 ++--- 15 files changed, 32 insertions(+), 48 deletions(-) diff --git a/docs/cli/plan-mode.md b/docs/cli/plan-mode.md index 149278f50b..617f8492fb 100644 --- a/docs/cli/plan-mode.md +++ b/docs/cli/plan-mode.md @@ -1,4 +1,4 @@ -# Plan Mode (experimental) +# Plan Mode Plan Mode is a read-only environment for architecting robust solutions before implementation. With Plan Mode, you can: @@ -8,27 +8,8 @@ implementation. With Plan Mode, you can: - **Design:** Understand problems, evaluate trade-offs, and choose a solution. - **Plan:** Align on an execution strategy before any code is modified. -> **Note:** This is a preview feature currently under active development. Your -> feedback is invaluable as we refine this feature. If you have ideas, -> suggestions, or encounter issues: -> -> - [Open an issue] on GitHub. -> - Use the **/bug** command within Gemini CLI to file an issue. - -## How to enable Plan Mode - -Enable Plan Mode in **Settings** or by editing your configuration file. - -- **Settings:** Use the `/settings` command and set **Plan** to `true`. -- **Configuration:** Add the following to your `settings.json`: - - ```json - { - "experimental": { - "plan": true - } - } - ``` +Plan Mode is enabled by default. You can manage this setting using the +`/settings` command. ## How to enter Plan Mode diff --git a/docs/cli/settings.md b/docs/cli/settings.md index 182217fc0e..5565a5e1f6 100644 --- a/docs/cli/settings.md +++ b/docs/cli/settings.md @@ -144,7 +144,7 @@ they appear in the UI. | Enable Tool Output Masking | `experimental.toolOutputMasking.enabled` | Enables tool output masking to save tokens. | `true` | | Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` | | Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` | -| Plan | `experimental.plan` | Enable planning features (Plan Mode and tools). | `false` | +| Plan | `experimental.plan` | Enable Plan Mode. | `true` | | Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` | | Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` | diff --git a/docs/reference/commands.md b/docs/reference/commands.md index b23f545501..aafb8c8566 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -279,8 +279,8 @@ Slash commands provide meta-level control over the CLI itself. - **Description:** Switch to Plan Mode (read-only) and view the current plan if one has been generated. - - **Note:** This feature requires the `experimental.plan` setting to be - enabled in your configuration. + - **Note:** This feature is enabled by default. It can be disabled via the + `experimental.plan` setting in your configuration. - **Sub-commands:** - **`copy`**: - **Description:** Copy the currently approved plan to your clipboard. diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 9b89fe75a8..b1d1f7f021 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -1021,8 +1021,8 @@ their corresponding top-level category object in your `settings.json` file. - **Default:** `false` - **`experimental.plan`** (boolean): - - **Description:** Enable planning features (Plan Mode and tools). - - **Default:** `false` + - **Description:** Enable Plan Mode. + - **Default:** `true` - **Requires restart:** Yes - **`experimental.taskTracker`** (boolean): diff --git a/packages/cli/src/acp/acpClient.test.ts b/packages/cli/src/acp/acpClient.test.ts index 0922e3a510..e2fc0f0d33 100644 --- a/packages/cli/src/acp/acpClient.test.ts +++ b/packages/cli/src/acp/acpClient.test.ts @@ -172,7 +172,7 @@ describe('GeminiAgent', () => { unsubscribe: vi.fn(), }), getApprovalMode: vi.fn().mockReturnValue('default'), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), getGemini31LaunchedSync: vi.fn().mockReturnValue(false), getHasAccessToPreviewModel: vi.fn().mockReturnValue(false), getCheckpointingEnabled: vi.fn().mockReturnValue(false), @@ -650,7 +650,7 @@ describe('Session', () => { getMessageBus: vi.fn().mockReturnValue(mockMessageBus), setApprovalMode: vi.fn(), setModel: vi.fn(), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), getCheckpointingEnabled: vi.fn().mockReturnValue(false), getGitService: vi.fn().mockResolvedValue({} as GitService), waitForMcpInit: vi.fn(), diff --git a/packages/cli/src/acp/acpResume.test.ts b/packages/cli/src/acp/acpResume.test.ts index 37354af5c9..9668ef74f8 100644 --- a/packages/cli/src/acp/acpResume.test.ts +++ b/packages/cli/src/acp/acpResume.test.ts @@ -92,7 +92,7 @@ describe('GeminiAgent Session Resume', () => { getProjectTempDir: vi.fn().mockReturnValue('/tmp/project'), }, getApprovalMode: vi.fn().mockReturnValue('default'), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), getModel: vi.fn().mockReturnValue('gemini-pro'), getHasAccessToPreviewModel: vi.fn().mockReturnValue(false), getGemini31LaunchedSync: vi.fn().mockReturnValue(false), @@ -204,6 +204,11 @@ describe('GeminiAgent Session Resume', () => { name: 'YOLO', description: 'Auto-approves all tools', }, + { + id: ApprovalMode.PLAN, + name: 'Plan', + description: 'Read-only mode', + }, ], currentModeId: ApprovalMode.DEFAULT, }, diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index a66d5e6589..22ff209cb6 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -2622,13 +2622,13 @@ describe('loadCliConfig approval mode', () => { expect(config.getApprovalMode()).toBe(ApprovalMode.DEFAULT); }); - it('should throw error when --approval-mode=plan is used but experimental.plan setting is missing', async () => { + it('should allow plan approval mode by default when --approval-mode=plan is used', async () => { process.argv = ['node', 'script.js', '--approval-mode', 'plan']; const argv = await parseArguments(createTestMergedSettings()); const settings = createTestMergedSettings({}); const config = await loadCliConfig(settings, 'test-session', argv); - expect(config.getApprovalMode()).toBe(ApprovalMode.DEFAULT); + expect(config.getApprovalMode()).toBe(ApprovalMode.PLAN); }); it('should pass planSettings.directory from settings to config', async () => { diff --git a/packages/cli/src/config/settingsSchema.test.ts b/packages/cli/src/config/settingsSchema.test.ts index 389cabe3cf..53d75bd436 100644 --- a/packages/cli/src/config/settingsSchema.test.ts +++ b/packages/cli/src/config/settingsSchema.test.ts @@ -424,12 +424,10 @@ describe('SettingsSchema', () => { expect(setting).toBeDefined(); expect(setting.type).toBe('boolean'); expect(setting.category).toBe('Experimental'); - expect(setting.default).toBe(false); + expect(setting.default).toBe(true); expect(setting.requiresRestart).toBe(true); expect(setting.showInDialog).toBe(true); - expect(setting.description).toBe( - 'Enable planning features (Plan Mode and tools).', - ); + expect(setting.description).toBe('Enable Plan Mode.'); }); it('should have hooksConfig.notifications setting in schema', () => { diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 4fa17916c4..bd1f9d82a4 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -1823,8 +1823,8 @@ const SETTINGS_SCHEMA = { label: 'Plan', category: 'Experimental', requiresRestart: true, - default: false, - description: 'Enable planning features (Plan Mode and tools).', + default: true, + description: 'Enable Plan Mode.', showInDialog: true, }, taskTracker: { diff --git a/packages/cli/src/services/BuiltinCommandLoader.test.ts b/packages/cli/src/services/BuiltinCommandLoader.test.ts index 7b7832bfbe..6eb27862e3 100644 --- a/packages/cli/src/services/BuiltinCommandLoader.test.ts +++ b/packages/cli/src/services/BuiltinCommandLoader.test.ts @@ -151,7 +151,7 @@ describe('BuiltinCommandLoader', () => { vi.clearAllMocks(); mockConfig = { getFolderTrust: vi.fn().mockReturnValue(true), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), getEnableExtensionReloading: () => false, getEnableHooks: () => false, getEnableHooksUI: () => false, @@ -351,7 +351,7 @@ describe('BuiltinCommandLoader profile', () => { vi.resetModules(); mockConfig = { getFolderTrust: vi.fn().mockReturnValue(false), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), getCheckpointingEnabled: () => false, getEnableExtensionReloading: () => false, getEnableHooks: () => false, diff --git a/packages/cli/src/ui/components/Composer.test.tsx b/packages/cli/src/ui/components/Composer.test.tsx index 9a6155da00..b1f804dd42 100644 --- a/packages/cli/src/ui/components/Composer.test.tsx +++ b/packages/cli/src/ui/components/Composer.test.tsx @@ -231,7 +231,7 @@ const createMockConfig = (overrides = {}): Config => getDebugMode: vi.fn(() => false), getAccessibility: vi.fn(() => ({})), getMcpServers: vi.fn(() => ({})), - isPlanEnabled: vi.fn(() => false), + isPlanEnabled: vi.fn(() => true), getToolRegistry: () => ({ getTool: vi.fn(), }), diff --git a/packages/cli/src/ui/hooks/useApprovalModeIndicator.test.ts b/packages/cli/src/ui/hooks/useApprovalModeIndicator.test.ts index 08ddd362f7..10d36ae01f 100644 --- a/packages/cli/src/ui/hooks/useApprovalModeIndicator.test.ts +++ b/packages/cli/src/ui/hooks/useApprovalModeIndicator.test.ts @@ -86,7 +86,7 @@ describe('useApprovalModeIndicator', () => { (value: ApprovalMode) => void >, isYoloModeDisabled: vi.fn().mockReturnValue(false), - isPlanEnabled: vi.fn().mockReturnValue(false), + isPlanEnabled: vi.fn().mockReturnValue(true), isTrustedFolder: vi.fn().mockReturnValue(true) as Mock<() => boolean>, getCoreTools: vi.fn().mockReturnValue([]) as Mock<() => string[]>, getToolDiscoveryCommand: vi.fn().mockReturnValue(undefined) as Mock< diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index 31e081c350..fc262e2b13 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -2788,9 +2788,9 @@ describe('Config Quota & Preview Model Access', () => { }); describe('isPlanEnabled', () => { - it('should return false by default', () => { + it('should return true by default', () => { const config = new Config(baseParams); - expect(config.isPlanEnabled()).toBe(false); + expect(config.isPlanEnabled()).toBe(true); }); it('should return true when plan is enabled', () => { diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index e3201aa521..775547e3ec 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -885,7 +885,7 @@ export class Config implements McpContext { this.enableAgents = params.enableAgents ?? false; this.agents = params.agents ?? {}; this.disableLLMCorrection = params.disableLLMCorrection ?? true; - this.planEnabled = params.plan ?? false; + this.planEnabled = params.plan ?? true; this.trackerEnabled = params.tracker ?? false; this.planModeRoutingEnabled = params.planSettings?.modelRouting ?? true; this.enableEventDrivenScheduler = params.enableEventDrivenScheduler ?? true; diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json index b2ef942711..280ad18db5 100644 --- a/schemas/settings.schema.json +++ b/schemas/settings.schema.json @@ -1712,9 +1712,9 @@ }, "plan": { "title": "Plan", - "description": "Enable planning features (Plan Mode and tools).", - "markdownDescription": "Enable planning features (Plan Mode and tools).\n\n- Category: `Experimental`\n- Requires restart: `yes`\n- Default: `false`", - "default": false, + "description": "Enable Plan Mode.", + "markdownDescription": "Enable Plan Mode.\n\n- Category: `Experimental`\n- Requires restart: `yes`\n- Default: `true`", + "default": true, "type": "boolean" }, "taskTracker": {