diff --git a/docs/get-started/configuration.md b/docs/get-started/configuration.md
index e3415eccfa..567bde0894 100644
--- a/docs/get-started/configuration.md
+++ b/docs/get-started/configuration.md
@@ -731,6 +731,11 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes
+- **`security.enablePermanentToolApproval`** (boolean):
+ - **Description:** Enable the "Allow for all future sessions" option in tool
+ confirmation dialogs.
+ - **Default:** `false`
+
- **`security.blockGitExtensions`** (boolean):
- **Description:** Blocks installing and loading extensions from Git.
- **Default:** `false`
diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts
index 5b8f75af60..ee2a9d3824 100644
--- a/packages/cli/src/config/settingsSchema.ts
+++ b/packages/cli/src/config/settingsSchema.ts
@@ -1164,6 +1164,16 @@ const SETTINGS_SCHEMA = {
description: 'Disable YOLO mode, even if enabled by a flag.',
showInDialog: true,
},
+ enablePermanentToolApproval: {
+ type: 'boolean',
+ label: 'Allow Permanent Tool Approval',
+ category: 'Security',
+ requiresRestart: false,
+ default: false,
+ description:
+ 'Enable the "Allow for all future sessions" option in tool confirmation dialogs.',
+ showInDialog: true,
+ },
blockGitExtensions: {
type: 'boolean',
label: 'Blocks extensions from Git',
diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.test.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.test.tsx
index 4063af9116..0291396e63 100644
--- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.test.tsx
+++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.test.tsx
@@ -10,7 +10,10 @@ import type {
ToolCallConfirmationDetails,
Config,
} from '@google/gemini-cli-core';
-import { renderWithProviders } from '../../../test-utils/render.js';
+import {
+ renderWithProviders,
+ createMockSettings,
+} from '../../../test-utils/render.js';
describe('ToolConfirmationMessage', () => {
const mockConfig = {
@@ -159,4 +162,63 @@ describe('ToolConfirmationMessage', () => {
});
});
});
+
+ describe('enablePermanentToolApproval setting', () => {
+ const editConfirmationDetails: ToolCallConfirmationDetails = {
+ type: 'edit',
+ title: 'Confirm Edit',
+ fileName: 'test.txt',
+ filePath: '/test.txt',
+ fileDiff: '...diff...',
+ originalContent: 'a',
+ newContent: 'b',
+ onConfirm: vi.fn(),
+ };
+
+ it('should NOT show "Allow for all future sessions" when setting is false (default)', () => {
+ const mockConfig = {
+ isTrustedFolder: () => true,
+ getIdeMode: () => false,
+ } as unknown as Config;
+
+ const { lastFrame } = renderWithProviders(
+ ,
+ {
+ settings: createMockSettings({
+ security: { enablePermanentToolApproval: false },
+ }),
+ },
+ );
+
+ expect(lastFrame()).not.toContain('Allow for all future sessions');
+ });
+
+ it('should show "Allow for all future sessions" when setting is true', () => {
+ const mockConfig = {
+ isTrustedFolder: () => true,
+ getIdeMode: () => false,
+ } as unknown as Config;
+
+ const { lastFrame } = renderWithProviders(
+ ,
+ {
+ settings: createMockSettings({
+ security: { enablePermanentToolApproval: true },
+ }),
+ },
+ );
+
+ expect(lastFrame()).toContain('Allow for all future sessions');
+ });
+ });
});
diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
index 17b4477067..5be9169f02 100644
--- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
@@ -20,6 +20,7 @@ import { MaxSizedBox } from '../shared/MaxSizedBox.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { theme } from '../../semantic-colors.js';
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
+import { useSettings } from '../../contexts/SettingsContext.js';
export interface ToolConfirmationMessageProps {
confirmationDetails: ToolCallConfirmationDetails;
@@ -41,6 +42,9 @@ export const ToolConfirmationMessage: React.FC<
const { onConfirm } = confirmationDetails;
const isAlternateBuffer = useAlternateBuffer();
+ const settings = useSettings();
+ const allowPermanentApproval =
+ settings.merged.security?.enablePermanentToolApproval ?? false;
const [ideClient, setIdeClient] = useState(null);
const [isDiffingEnabled, setIsDiffingEnabled] = useState(false);
@@ -112,11 +116,13 @@ export const ToolConfirmationMessage: React.FC<
value: ToolConfirmationOutcome.ProceedAlways,
key: 'Allow for this session',
});
- options.push({
- label: 'Allow for all future sessions',
- value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
- key: 'Allow for all future sessions',
- });
+ if (allowPermanentApproval) {
+ options.push({
+ label: 'Allow for all future sessions',
+ value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
+ key: 'Allow for all future sessions',
+ });
+ }
}
if (!config.getIdeMode() || !isDiffingEnabled) {
options.push({
@@ -147,11 +153,13 @@ export const ToolConfirmationMessage: React.FC<
value: ToolConfirmationOutcome.ProceedAlways,
key: `Allow for this session`,
});
- options.push({
- label: `Allow for all future sessions`,
- value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
- key: `Allow for all future sessions`,
- });
+ if (allowPermanentApproval) {
+ options.push({
+ label: `Allow for all future sessions`,
+ value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
+ key: `Allow for all future sessions`,
+ });
+ }
}
options.push({
label: 'No, suggest changes (esc)',
@@ -171,11 +179,13 @@ export const ToolConfirmationMessage: React.FC<
value: ToolConfirmationOutcome.ProceedAlways,
key: 'Allow for this session',
});
- options.push({
- label: 'Allow for all future sessions',
- value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
- key: 'Allow for all future sessions',
- });
+ if (allowPermanentApproval) {
+ options.push({
+ label: 'Allow for all future sessions',
+ value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
+ key: 'Allow for all future sessions',
+ });
+ }
}
options.push({
label: 'No, suggest changes (esc)',
@@ -202,11 +212,13 @@ export const ToolConfirmationMessage: React.FC<
value: ToolConfirmationOutcome.ProceedAlwaysServer,
key: 'Allow all server tools for this session',
});
- options.push({
- label: 'Allow tool for all future sessions',
- value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
- key: 'Allow tool for all future sessions',
- });
+ if (allowPermanentApproval) {
+ options.push({
+ label: 'Allow tool for all future sessions',
+ value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
+ key: 'Allow tool for all future sessions',
+ });
+ }
}
options.push({
label: 'No, suggest changes (esc)',
@@ -327,6 +339,7 @@ export const ToolConfirmationMessage: React.FC<
availableTerminalHeight,
terminalWidth,
isAlternateBuffer,
+ allowPermanentApproval,
]);
if (confirmationDetails.type === 'edit') {
diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
index ee1e15763e..b36523715a 100644
--- a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
+++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
@@ -4,7 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { renderWithProviders } from '../../../test-utils/render.js';
+import {
+ renderWithProviders,
+ createMockSettings,
+} from '../../../test-utils/render.js';
import { describe, it, expect, vi } from 'vitest';
import { ToolGroupMessage } from './ToolGroupMessage.js';
import type { IndividualToolCallDisplay } from '../../types.js';
@@ -376,5 +379,57 @@ describe('', () => {
expect(lastFrame()).toMatchSnapshot();
unmount();
});
+
+ it('renders confirmation with permanent approval enabled', () => {
+ const toolCalls = [
+ createToolCall({
+ callId: 'tool-1',
+ name: 'confirm-tool',
+ status: ToolCallStatus.Confirming,
+ confirmationDetails: {
+ type: 'info',
+ title: 'Confirm Tool',
+ prompt: 'Do you want to proceed?',
+ onConfirm: vi.fn(),
+ },
+ }),
+ ];
+ const settings = createMockSettings({
+ security: { enablePermanentToolApproval: true },
+ });
+ const { lastFrame, unmount } = renderWithProviders(
+ ,
+ { settings },
+ );
+ expect(lastFrame()).toContain('Allow for all future sessions');
+ expect(lastFrame()).toMatchSnapshot();
+ unmount();
+ });
+
+ it('renders confirmation with permanent approval disabled', () => {
+ const toolCalls = [
+ createToolCall({
+ callId: 'tool-1',
+ name: 'confirm-tool',
+ status: ToolCallStatus.Confirming,
+ confirmationDetails: {
+ type: 'info',
+ title: 'Confirm Tool',
+ prompt: 'Do you want to proceed?',
+ onConfirm: vi.fn(),
+ },
+ }),
+ ];
+ const settings = createMockSettings({
+ security: { enablePermanentToolApproval: false },
+ });
+ const { lastFrame, unmount } = renderWithProviders(
+ ,
+ { settings },
+ );
+ expect(lastFrame()).not.toContain('Allow for all future sessions');
+ expect(lastFrame()).toMatchSnapshot();
+ unmount();
+ });
});
});
diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolConfirmationMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolConfirmationMessage.test.tsx.snap
index 9187fad554..d89a4686eb 100644
--- a/packages/cli/src/ui/components/messages/__snapshots__/ToolConfirmationMessage.test.tsx.snap
+++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolConfirmationMessage.test.tsx.snap
@@ -10,8 +10,7 @@ Do you want to proceed?
● 1. Allow once
2. Allow for this session
- 3. Allow for all future sessions
- 4. No, suggest changes (esc)
+ 3. No, suggest changes (esc)
"
`;
@@ -22,8 +21,7 @@ Do you want to proceed?
● 1. Allow once
2. Allow for this session
- 3. Allow for all future sessions
- 4. No, suggest changes (esc)
+ 3. No, suggest changes (esc)
"
`;
@@ -53,9 +51,8 @@ Apply this change?
● 1. Allow once
2. Allow for this session
- 3. Allow for all future sessions
- 4. Modify with external editor
- 5. No, suggest changes (esc)
+ 3. Modify with external editor
+ 4. No, suggest changes (esc)
"
`;
@@ -76,8 +73,7 @@ Allow execution of: 'echo'?
● 1. Allow once
2. Allow for this session
- 3. Allow for all future sessions
- 4. No, suggest changes (esc)
+ 3. No, suggest changes (esc)
"
`;
@@ -98,8 +94,7 @@ Do you want to proceed?
● 1. Allow once
2. Allow for this session
- 3. Allow for all future sessions
- 4. No, suggest changes (esc)
+ 3. No, suggest changes (esc)
"
`;
@@ -123,7 +118,6 @@ Allow execution of MCP tool "test-tool" from server "test-server"?
● 1. Allow once
2. Allow tool for this session
3. Allow all server tools for this session
- 4. Allow tool for all future sessions
- 5. No, suggest changes (esc)
+ 4. No, suggest changes (esc)
"
`;
diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
index 7133df2b58..6bea5eecd5 100644
--- a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
+++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
@@ -28,6 +28,39 @@ exports[` > Border Color Logic > uses yellow border when too
╰──────────────────────────────────────────────────────────────────────────────╯"
`;
+exports[` > Confirmation Handling > renders confirmation with permanent approval disabled 1`] = `
+"╭──────────────────────────────────────────────────────────────────────────────╮
+│ ? confirm-tool A tool for testing ← │
+│ │
+│ Test result │
+│ Do you want to proceed? │
+│ │
+│ Do you want to proceed? │
+│ │
+│ ● 1. Allow once │
+│ 2. Allow for this session │
+│ 3. No, suggest changes (esc) │
+│ │
+╰──────────────────────────────────────────────────────────────────────────────╯"
+`;
+
+exports[` > Confirmation Handling > renders confirmation with permanent approval enabled 1`] = `
+"╭──────────────────────────────────────────────────────────────────────────────╮
+│ ? confirm-tool A tool for testing ← │
+│ │
+│ Test result │
+│ Do you want to proceed? │
+│ │
+│ Do you want to proceed? │
+│ │
+│ ● 1. Allow once │
+│ 2. Allow for this session │
+│ 3. Allow for all future sessions │
+│ 4. No, suggest changes (esc) │
+│ │
+╰──────────────────────────────────────────────────────────────────────────────╯"
+`;
+
exports[` > Confirmation Handling > shows confirmation dialog for first confirming tool only 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ? first-confirm A tool for testing ← │
@@ -39,8 +72,7 @@ exports[` > Confirmation Handling > shows confirmation dialo
│ │
│ ● 1. Allow once │
│ 2. Allow for this session │
-│ 3. Allow for all future sessions │
-│ 4. No, suggest changes (esc) │
+│ 3. No, suggest changes (esc) │
│ │
│ │
│ ? second-confirm A tool for testing │
@@ -123,8 +155,7 @@ exports[` > Golden Snapshots > renders tool call awaiting co
│ │
│ ● 1. Allow once │
│ 2. Allow for this session │
-│ 3. Allow for all future sessions │
-│ 4. No, suggest changes (esc) │
+│ 3. No, suggest changes (esc) │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯"
`;
diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json
index 7570abe6b8..b391496aa6 100644
--- a/schemas/settings.schema.json
+++ b/schemas/settings.schema.json
@@ -1200,6 +1200,13 @@
"default": false,
"type": "boolean"
},
+ "enablePermanentToolApproval": {
+ "title": "Allow Permanent Tool Approval",
+ "description": "Enable the \"Allow for all future sessions\" option in tool confirmation dialogs.",
+ "markdownDescription": "Enable the \"Allow for all future sessions\" option in tool confirmation dialogs.\n\n- Category: `Security`\n- Requires restart: `no`\n- Default: `false`",
+ "default": false,
+ "type": "boolean"
+ },
"blockGitExtensions": {
"title": "Blocks extensions from Git",
"description": "Blocks installing and loading extensions from Git.",