Skip to content

feat(core): add configurable delay for shell commands in YOLO mode#25028

Open
jardondiego wants to merge 5 commits intogoogle-gemini:mainfrom
jardondiego:feat/yolo-shell-delay
Open

feat(core): add configurable delay for shell commands in YOLO mode#25028
jardondiego wants to merge 5 commits intogoogle-gemini:mainfrom
jardondiego:feat/yolo-shell-delay

Conversation

@jardondiego
Copy link
Copy Markdown

Summary

Adds a configurable delay (security.yoloShellDelayMs) before automatically
executing shell commands when the CLI is in YOLO mode. The delay natively
supports an interactive countdown in the CLI, allowing users to safely cancel
(Ctrl+C) dangerous commands without them executing. The default value is 0
(disabled) to maintain backwards compatibility.

Details

  • Configuration Layer: Added yoloShellDelayMs to settingsSchema.json and
    passed it down to the Config singleton in @google/gemini-cli-core.
  • Tool Execution: Modified ShellToolInvocation.execute to intercept YOLO
    mode shell commands (unless they are background commands) and display a
    1-second interval countdown using the updateOutput callback.
  • Cancellation: Hooked into the AbortSignal during the countdown. If the
    user hits Ctrl+C before the timer expires, the tool returns early and avoids
    shelling out.
  • Tests: Added comprehensive unit tests in shell.test.ts utilizing
    vi.useFakeTimers() to ensure accurate timing and correct cancellation
    handling.

Related Issues

How to Validate

  1. In settings.json, add "security": { "yoloShellDelayMs": 3000 }.
  2. Start the CLI with --yolo flag.
  3. Prompt it to run a shell command (e.g. Run ls -la).
  4. You should see a countdown:
    [YOLO] Executing in 3s... (Press Ctrl+C to cancel).
  5. Try cancelling the command during the countdown to ensure it doesn't run.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@jardondiego jardondiego requested review from a team as code owners April 9, 2026 14:30
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

🛑 Action Required: Evaluation Approval

Steering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged.

Maintainers:

  1. Go to the Workflow Run Summary.
  2. Click the yellow 'Review deployments' button.
  3. Select the 'eval-gate' environment and click 'Approve'.

Once approved, the evaluation results will be posted here automatically.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the security of the CLI's YOLO mode by introducing a configurable delay before shell commands are executed. This change provides a critical safety window for users to review and cancel potentially dangerous commands, significantly reducing the risk of accidental execution.

Highlights

  • Configurable Delay: Introduced a new configuration setting, security.yoloShellDelayMs, allowing users to define a delay before shell commands execute in YOLO mode.
  • Interactive Countdown: Implemented a countdown mechanism in the CLI that provides visual feedback and allows users to safely cancel commands using Ctrl+C.
  • Comprehensive Testing: Added unit tests using vi.useFakeTimers() to verify the timing logic and ensure that command cancellation works as expected.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new security.yoloShellDelayMs configuration setting, enabling a configurable delay before shell commands execute in YOLO mode. This feature includes an interactive countdown in the CLI, allowing users to cancel commands during the delay. The review feedback points out that the current setInterval implementation for the delay is imprecise, rounding up to the nearest second, and suggests an alternative recursive setTimeout approach for more accurate millisecond timing.

Comment on lines +457 to +496
if (isYoloMode && delayMs > 0 && !this.params.is_background) {
let countdownInterval: NodeJS.Timeout | undefined;
let countdownMs = delayMs;
const updateIntervalMs = 1000;

try {
await new Promise<void>((resolve, reject) => {
const onAbort = () => {
if (countdownInterval) clearInterval(countdownInterval);
reject(new Error('Command cancelled by user during YOLO delay.'));
};
signal.addEventListener('abort', onAbort, { once: true });

if (updateOutput) {
updateOutput(
`[YOLO] Executing in ${Math.ceil(countdownMs / 1000)}s... (Press Ctrl+C to cancel)\n`,
);
}

countdownInterval = setInterval(() => {
countdownMs -= updateIntervalMs;
if (countdownMs <= 0) {
clearInterval(countdownInterval);
signal.removeEventListener('abort', onAbort);
resolve();
} else if (updateOutput) {
updateOutput(
`[YOLO] Executing in ${Math.ceil(countdownMs / 1000)}s... (Press Ctrl+C to cancel)\n`,
);
}
}, updateIntervalMs);
});
} catch {
return {
llmContent:
'Command was cancelled by user during the YOLO mode delay.',
returnDisplay: 'Command cancelled by user.',
};
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of the YOLO mode delay using setInterval is not precise and will always round the delay up to the nearest second. For example, a configured delay of 2500ms will result in an actual delay of 3000ms. This can be confusing for users who expect millisecond precision as implied by the yoloShellDelayMs setting name.

To ensure the delay is accurate, I suggest using a recursive setTimeout approach that calculates the remaining time based on the current time. This will respect the configured millisecond value precisely.

    if (isYoloMode && delayMs > 0 && !this.params.is_background) {
      try {
        await new Promise<void>((resolve, reject) => {
          const endTime = Date.now() + delayMs;
          let timeout: NodeJS.Timeout;

          const onAbort = () => {
            clearTimeout(timeout);
            reject(new Error('Command cancelled by user during YOLO delay.'));
          };
          signal.addEventListener('abort', onAbort, { once: true });

          const tick = () => {
            const remainingMs = Math.max(0, endTime - Date.now());

            if (updateOutput) {
              updateOutput(
                `[YOLO] Executing in ${Math.ceil(
                  remainingMs / 1000,
                )}s... (Press Ctrl+C to cancel)\n`,
              );
            }

            if (remainingMs <= 0) {
              signal.removeEventListener('abort', onAbort);
              resolve();
            } else {
              timeout = setTimeout(tick, Math.min(remainingMs, 1000));
            }
          };

          tick();
        });
      } catch {
        return {
          llmContent:
            'Command was cancelled by user during the YOLO mode delay.',
          returnDisplay: 'Command cancelled by user.',
        };
      }
    }
References
  1. The suggested code correctly utilizes AbortSignal for cancellation of the asynchronous delay, aligning with the principle that asynchronous operations should rely on AbortSignal for cancellation to maintain consistency with existing patterns.

@gemini-cli gemini-cli bot added the priority/p1 Important and should be addressed in the near term. label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/p1 Important and should be addressed in the near term.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant