gemini-cli icon indicating copy to clipboard operation
gemini-cli copied to clipboard

feat: Implement background shell commands

Open galz10 opened this issue 3 weeks ago • 7 comments

Summary

Implement support for running shell commands in the background. This feature allows long-running commands to execute without blocking the CLI, improving responsiveness.

Details

This PR introduces the capability to execute shell commands asynchronously. Previously, all shell commands were blocking, which could lead to a poor user experience for operations that take a significant amount of time. This change leverages process management to run commands in a non-blocking manner, allowing the CLI to remain interactive. The output of background commands can be retrieved as they become available.

Related Issues

Related to #<issue_number>

How to Validate

Validate ShellTool

  1. Run a long-running shell command using the new background command functionality, (e.g "please run npm run preflight in the background", "please run a shell command that sleeps for 10min in the background")
  2. Verify that the CLI remains responsive and does not block while the command is running in the background.
  3. press ctrl+b to view the background process

Validate ShellCommandProcessor

  1. Press Shift+! to enter shell mode
  2. execute any command that will wait for user input (vim, nvim, gemini)
  3. press ctrl+b to put it in the background
  4. press ctrl+b to view the background process
  5. Verify that the CLI remains responsive and does not block while the command is running in the background.

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

galz10 avatar Dec 09 '25 20:12 galz10

Summary of Changes

Hello @galz10, I'm Gemini Code Assist[^1]! 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 introduces a new feature that allows users to execute shell commands in the background, significantly enhancing the CLI's multitasking capabilities. It provides a dedicated user interface for monitoring and interacting with these background processes, complete with new keybindings for seamless management. The underlying shell execution service has been extensively refactored to support persistent background processes, real-time output streaming, and lifecycle management, while the run_shell_command tool has been updated to enable AI models to leverage this new functionality.

Highlights

  • Background Shell Execution: Introduced the capability to run shell commands in the background, allowing long-running processes to operate without blocking the main user interface.
  • Dedicated UI for Background Shells: A new BackgroundShellDisplay component has been added to visualize and interact with active background processes, including their output and the ability to switch between them.
  • New Keybindings for Management: Added Ctrl+B to either move the current foreground shell command to the background or toggle the visibility of the background shell view. Ctrl+O was also introduced to toggle a list of all active background shell processes.
  • Enhanced Shell Execution Service: The core ShellExecutionService has been significantly upgraded to manage persistent background PTYs, provide real-time output updates via subscriptions, handle process exit events, and allow explicit termination of background processes.
  • Tool Integration: The run_shell_command tool now supports an is_background parameter, enabling AI models to initiate and manage tasks that run in the background.
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 :thumbsup: and :thumbsdown: 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

[^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.

gemini-code-assist[bot] avatar Dec 09 '25 20:12 gemini-code-assist[bot]

Thanks for your hard work on this pull request!

This pull request is quite large, which can make it challenging and time-consuming for reviewers to go through thoroughly.

To help us review it more efficiently and get your changes merged faster, we kindly request you consider breaking this into smaller, more focused pull requests. Each smaller PR should ideally address a single logical change or a small set of related changes.

For example, you could separate out refactoring, new feature additions, and bug fixes into individual PRs. This makes it easier to understand, review, and test each component independently.

We appreciate your understanding and cooperation. Feel free to reach out if you need any assistance with this!

gemini-cli[bot] avatar Dec 09 '25 20:12 gemini-cli[bot]

Size Change: +26.7 kB (+0.12%)

Total Size: 21.6 MB

Filename Size Change
./bundle/gemini.js 21.6 MB +26.7 kB (+0.12%)
ℹ️ View Unchanged
Filename Size
./bundle/sandbox-macos-permissive-closed.sb 1.03 kB
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-closed.sb 3.29 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB

compressed-size-action

github-actions[bot] avatar Dec 09 '25 22:12 github-actions[bot]

Hello! This is a fantastic feature addition. The implementation of background shell commands is a significant UX improvement for long-running tasks. The architecture using ShellExecutionService to detach the PTY is clever.

I have a few critical comments regarding React best practices (specifically hooks), process lifecycle management, and potential keybinding conflicts.

Critical Issues

  1. Forbidden eslint-disable in BackgroundShellDisplay.tsx: In packages/cli/src/ui/components/BackgroundShellDisplay.tsx, you have disabled the exhaustive deps rule:

    // We only want this to run on mount (when the component becomes visible)
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);
    

    We explicitly forbid disabling react-hooks/exhaustive-deps. This often leads to stale closures and bugs that are hard to debug. Fix: Move this logic up to AppContainer.tsx. You already have toggleBackgroundShell and setIsBackgroundShellListOpen. When the background shell view is toggled on (e.g., in the key handler or a specific effect in AppContainer that watches isBackgroundShellVisible transitions), you can check the number of shells and decide whether to open the list or not. This keeps the child component pure and the logic where state is managed.

  2. setTimeout preventing process exit in ShellExecutionService.ts: In packages/core/src/services/shellExecutionService.ts:

    setTimeout(
      () => {
        this.exitedPtyInfo.delete(ptyProcess.pid);
      },
      5 * 60 * 1000,
    );
    

    This 5-minute timer is likely to keep the Node.js event loop alive, preventing the CLI from exiting gracefully if the user tries to quit while this timer is active. Fix: Chain .unref() to the timeout: setTimeout(...).unref().

Code Quality & Best Practices

  1. Keyboard Shortcut (F11): F11 is the standard shortcut for "Toggle Full Screen" in many terminal emulators and operating systems (including macOS "Show Desktop" and VSCode). This is likely to conflict. Suggestion: The PR description mentions Ctrl+B. Consider using that if available, or Ctrl+Alt+B? If F11 is strongly desired, please document the potential conflicts or verify it works in major environments (VSCode, iTerm2, Windows Terminal).

  2. Type Safety in useGeminiStream.ts:

    const data = response?.data as unknown as ShellToolData;
    

    Please avoid double casting with unknown. Define the ShellToolData interface clearly or import it if possible, and assert the type safely or use a type guard.

  3. BackgroundShellDisplay Effect Dependencies: The effect that calls ShellExecutionService.resizePty depends on width and height. Ensure that resizePty is debounced or efficient enough that resizing the terminal window doesn't cause excessive IPC/PTY calls, although ink's render cycle usually dampens this enough.

Tests

  1. Integration Tests: The unit tests look good, but this is a complex feature involving IPC and PTY management. Request: Please add an integration test in integration-tests/ (e.g., background-shell.test.ts) that:

    • Starts the CLI.
    • Runs a command like sleep 1.
    • Backgrounds it.
    • Verifies the UI shows the background indicator.
    • Verifies the process eventually exits. This ensures the end-to-end flow works as expected.
  2. Test Utilities: In packages/cli/src/ui/components/BackgroundShellDisplay.test.tsx, you are using act from react alongside render from the test utils. This is generally correct given our custom render, but please double-check that you aren't getting any "not wrapped in act" warnings in the console when running these tests.

Great work on a complex feature! Looking forward to the updates.

jacob314 avatar Dec 12 '25 21:12 jacob314

@galz10 Ctrl+b is not opening/showing background processes even though UI shows there is one.

image

jackwotherspoon avatar Dec 15 '25 12:12 jackwotherspoon

I am still uncertain whether the Using: 2 GEMINI.md files | 1 Background process is visually enough for users to notice there is a background process.

Is there a world where we want the 1 Background process to be the same color as shell mode border? Would be more noticeable and make it more clear that background processes equate to background shells.

maybe @jacob314 has thoughts on this?

jackwotherspoon avatar Dec 15 '25 12:12 jackwotherspoon

When a process is moved to the background we need to surface the shortcut to show background commands to the user...

Command moved to background. View background processes using "shortcut"

image

Otherwise the user has no idea how to view their shells 😄

jackwotherspoon avatar Dec 17 '25 01:12 jackwotherspoon