Skip to content

Persistent shell support#21475

Open
jacob314 wants to merge 1 commit intomainfrom
aliases
Open

Persistent shell support#21475
jacob314 wants to merge 1 commit intomainfrom
aliases

Conversation

@jacob314
Copy link
Contributor

@jacob314 jacob314 commented Mar 6, 2026

Summary

Support aliases
Massively speed up running shell commands
Support setting env variables within shell commands with the expected behavior

Details

Related Issues

Fixes #21461

How to Validate

Define an alias in your profile
Validate you can now use it inside gemini cli
set env variables in one shell command and use them in the next

Possible bugs:
make sure things are still ok if you send shells to the background, execute and exit shell commands such as vim that use the alternate buffer.
Make sure shells are sized correctly and don't end up with stale size information due to the reuse.

@jacob314 jacob314 requested review from a team as code owners March 6, 2026 22:36
@gemini-cli
Copy link
Contributor

gemini-cli bot commented Mar 6, 2026

Hi @jacob314, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.

We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines.

Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.

Thank you for your understanding and for being a part of our community!

@gemini-code-assist
Copy link
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 introduces a fundamental enhancement to shell command execution by implementing persistent shell sessions. This change allows the shell environment, including variables, current working directory, and aliases, to be maintained between commands, providing a more natural and efficient interactive experience. It addresses limitations where each command previously ran in an isolated shell, losing context. The new functionality is configurable and enabled by default, ensuring that users benefit from a more consistent and powerful shell interaction.

Highlights

  • Persistent Shell Session: Introduced a new PersistentShellSession class that maintains a shell session across multiple command executions, preserving environment variables, directory changes, and aliases. This significantly improves the user experience by allowing commands to build upon previous shell state.
  • Configuration Option: Added a new configuration setting tools.shell.enablePersistentShell (defaulting to true) to allow users to enable or disable this persistent shell behavior. This setting requires a restart to take effect.
  • Shell Execution Integration: Integrated the PersistentShellSession into the ShellExecutionService and ShellToolInvocation to conditionally use the persistent session based on the new configuration. Command wrapping logic was adjusted to prevent premature exits in persistent sessions.
  • Zsh Support: Extended shell type detection to explicitly support zsh for better compatibility and configuration.
Changelog
  • docs/cli/settings.md
    • Added documentation for the new Enable Persistent Shell setting.
  • docs/reference/configuration.md
    • Added a detailed reference entry for the tools.shell.enablePersistentShell configuration option.
  • packages/cli/src/config/config.ts
    • Integrated the enablePersistentShell setting into the CLI configuration loading process.
  • packages/cli/src/config/settingsSchema.ts
    • Defined the schema for the new enablePersistentShell setting, including its type, label, category, restart requirement, default value, description, and visibility.
  • packages/cli/src/services/prompt-processors/shellProcessor.ts
    • Passed the persistent flag from the configuration to the shell execution service.
  • packages/cli/src/ui/hooks/shellCommandProcessor.test.tsx
    • Updated shell command processor tests to include the getEnablePersistentShell mock.
  • packages/cli/src/ui/hooks/shellCommandProcessor.ts
    • Implemented logic to retrieve the isPersistent setting and adjusted command wrapping for persistent shells to use (exit $__code) instead of exit $__code.
  • packages/core/src/config/config.ts
    • Added enablePersistentShell property to the ConfigParameters interface and Config class, including its initialization and a getter method.
  • packages/core/src/services/persistentShellSession.test.ts
    • Added a new test file with unit tests for the PersistentShellSession class, verifying command execution and state persistence.
  • packages/core/src/services/persistentShellSession.ts
    • Added a new file implementing the PersistentShellSession class, which manages a persistent PTY or child_process, handles command queuing, output streaming, and exit code parsing.
  • packages/core/src/services/shellExecutionService.ts
    • Imported PersistentShellSession and added a static instance to manage persistent shell sessions. Modified the execute method to conditionally use the persistent session and updated writeToPty and resizePty to interact with the persistent session if active.
  • packages/core/src/tools/shell.test.ts
    • Updated shell tool tests to include getEnablePersistentShell in the mocked configuration and adjusted expected shell execution parameters for persistent mode.
  • packages/core/src/tools/shell.ts
    • Introduced isPersistent flag to conditionally modify command wrapping for background processes and passed the persistent flag to the ShellExecutionConfig.
  • packages/core/src/utils/shell-utils.test.ts
    • Updated shell utility tests to explicitly set process.env['SHELL'] for consistent bash configuration testing on Linux and macOS.
  • packages/core/src/utils/shell-utils.ts
    • Extended the ShellType enum to include zsh for broader shell compatibility.
  • schemas/settings.schema.json
    • Updated the JSON schema to include the enablePersistentShell property under tools.shell, specifying its title, description, default value, and type.
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.

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.

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.

@github-actions
Copy link

github-actions bot commented Mar 6, 2026

Size Change: +18.9 kB (+0.07%)

Total Size: 26 MB

Filename Size Change
./bundle/gemini.js 25.5 MB +18.9 kB (+0.07%)
ℹ️ View Unchanged
Filename Size
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 221 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 227 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 11.5 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/types.js 132 B
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB
./bundle/sandbox-macos-strict-open.sb 4.82 kB
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB

compressed-size-action

Copy link
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 support for persistent shell sessions, a significant feature for maintaining state across shell commands. During the review, a critical command injection vulnerability was identified in the PersistentShellSession class where the current working directory (cwd) is unsafely interpolated into shell command strings, potentially allowing an attacker to execute arbitrary commands. This violates established guidelines for sanitizing user-provided file paths in file system operations. Additionally, a critical bug was found in the interactive shell command processor causing incorrect exit code reporting, and the persistent session's lack of resilience to exit commands can lead to unexpected state loss. Addressing these issues is crucial to ensure the feature is robust, reliable, and secure.

Comment on lines +296 to +300
if (isPersistent) {
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; (exit $__code)`;
} else {
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The command wrapping logic for persistent shells creates an incompatibility with the underlying PersistentShellSession. The commandToExecute is constructed with (exit $__code) to prevent the PTY from closing, but this command is then passed to PersistentShellSession, which has its own mechanism for capturing exit codes using markers and $?. The (exit) command runs in a subshell and does not set $? in the parent shell where PersistentShellSession is trying to read it. As a result, PersistentShellSession will likely always receive an exit code of 0, incorrectly reporting all commands as successful. This dual-wrapping approach breaks exit code reporting.

Comment on lines +401 to +406
wrappedCmd = `Set-Location "${cwd}"; Write-Output ("${start1}" + "${start2}"); try { ${command} } finally { Write-Output ("${prefix1}" + "${prefix2}$LASTEXITCODE${this.endMarkerSuffix}") }\r\n`;
} else if (this.shellType === 'cmd') {
wrappedCmd = `call echo ${start1}^${start2} & pushd "${cwd}" && ${command} & set __code=%errorlevel% & popd & call echo ${prefix1}^${prefix2}%__code%${this.endMarkerSuffix}\r\n`;
} else {
// bash/zsh
wrappedCmd = `echo "${start1}""${start2}"; cd "${cwd}" && { ${command.trim().replace(/;$/, '')}; }; echo "${prefix1}""${prefix2}$?${this.endMarkerSuffix}"\n`;
Copy link
Contributor

Choose a reason for hiding this comment

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

security-high high

A critical command injection vulnerability exists here: the cwd (current working directory) parameter is unsafely interpolated into a shell command string using double quotes. This allows command substitution, enabling an attacker to achieve arbitrary command execution if they can influence the directory path. To remediate, use the escapeShellArg utility to properly escape the cwd string.

Furthermore, the current implementation for executing commands in bash/zsh uses a command group { ... }, which makes the session vulnerable to exit commands. If exit is issued, the entire persistent shell process terminates, leading to state loss and defeating the purpose of a persistent shell. The session should be made resilient to exit commands to ensure reliable state persistence.

References
  1. Sanitize user-provided file paths used in file system operations to prevent path traversal vulnerabilities.
  2. Utility functions that perform file system operations should validate their path inputs internally to prevent path traversal vulnerabilities, rather than relying solely on callers to perform validation.

@gemini-cli gemini-cli bot added the 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item. label Mar 6, 2026
const startMarker1 = commandCall1
.match(/"___GEMINI""(_START_MARKER_[a-z0-9]+___)"/)[0]
.replace(/"/g, '')
.replace(/___GEMINI/, '___GEMINI');

Check warning

Code scanning / CodeQL

Replacement of a substring with itself Medium

This replaces '___GEMINI' with itself.
const startMarker2 = commandCall2
.match(/"___GEMINI""(_START_MARKER_[a-z0-9]+___)"/)[0]
.replace(/"/g, '')
.replace(/___GEMINI/, '___GEMINI');

Check warning

Code scanning / CodeQL

Replacement of a substring with itself Medium

This replaces '___GEMINI' with itself.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔒 maintainer only ⛔ Do not contribute. Internal roadmap item.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gemini CLI Shell Command does not support aliases

1 participant