Skip to content

feat(extensions): add support for custom themes in extensions#17327

Merged
spencer426 merged 16 commits into
mainfrom
feature/custom-themes
Jan 28, 2026
Merged

feat(extensions): add support for custom themes in extensions#17327
spencer426 merged 16 commits into
mainfrom
feature/custom-themes

Conversation

@spencer426

Copy link
Copy Markdown
Contributor

Summary

This PR introduces support for extensions to contribute custom themes to Gemini CLI. With this change, extensions can include a themes property
in their gemini-extension.json file. These themes will be automatically discovered, loaded, and made available for users to select from in the
theme dialog.
Screenshot 2026-01-22 at 9 56 03 AM

Details

To enable this functionality, the ExtensionManager has been updated to handle the registration and unregistration of themes as extensions are
activated or deactivated. The ThemeManager was refactored to manage themes from multiple origins—user settings, extensions, and direct file
paths—while ensuring proper namespacing to prevent any naming conflicts.

As a result, the ThemeDialog has been streamlined to source its list of themes directly from the ThemeManager. Additionally, the CustomTheme
interface has been relocated to @google/gemini-cli-core, making it accessible to extension developers.

Related Issues

Fixes #16192

How to Validate

  1. Create a new extension and, in its gemini-extension.json file, add a themes property with at least one custom theme. For example:
{
  "name": "my-custom-theme-extension",
  "version": "0.0.1",
  "themes": [
    {
      "name": "My-Awesome-Theme",
      "type": "custom",
      "text": {
        "primary": "#FF00FF"
      }
    }
  ]
}
        
  1. Install the extension in Gemini CLI using gemini extensions link PATH_TO_EXTENSION.
  2. Launch gemini and open the theme selection dialog using /theme.
  3. Confirm that the new theme (e.g., my-theme-extension: My-Awesome-Theme) is listed.
  4. Select the theme and verify that its styles are correctly applied.
  5. Uninstall the extension.
  6. Re-open the theme selection dialog and ensure the theme has been removed from the list.

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
      • [ x] npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@spencer426 spencer426 requested a review from a team as a code owner January 22, 2026 18:45
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @spencer426, 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 significant enhancement to the Gemini CLI by enabling extensions to provide their own custom themes. This allows for greater personalization and integration within the CLI ecosystem. The core changes involve updating the extension and theme management systems to seamlessly handle these new theme contributions, ensuring they are correctly loaded, displayed, and managed without conflicts, ultimately enriching the user experience with more diverse visual options.

Highlights

  • Extension Theme Support: Extensions can now contribute custom themes to the Gemini CLI by including a 'themes' property in their 'gemini-extension.json' file.
  • Automated Theme Management: The ExtensionManager automatically discovers, registers, and unregisters these themes as extensions are activated or deactivated.
  • Refactored ThemeManager: The ThemeManager has been updated to manage themes from various origins (user settings, extensions, file paths) with proper namespacing to prevent conflicts.
  • Streamlined ThemeDialog: The ThemeDialog now directly sources all available themes from the ThemeManager, simplifying its logic and consolidating theme display.
  • CustomTheme Interface Relocation: The 'CustomTheme' interface has been moved to '@google/gemini-cli-core', making it readily accessible for extension developers.
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.

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

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.

Code Review

The pull request introduces support for custom themes in extensions, allowing extensions to contribute themes that are automatically discovered and managed by the CLI. The ExtensionManager and ThemeManager have been updated to handle the registration and unregistration of these themes, including proper namespacing to prevent conflicts. The ThemeDialog has been streamlined to source themes directly from the ThemeManager, and the CustomTheme interface has been moved to @google/gemini-cli-core for broader accessibility. Tests have been added to cover the new theme loading functionality.

Overall, the changes are well-structured and implement the new feature effectively. However, there are a couple of areas that could be improved for better adherence to best practices and test maintainability, specifically regarding the use of synchronous file system operations in tests and proper cleanup of environment variables to ensure test isolation.

Comment on lines +20 to +21
const tempHomeDir = fs.mkdtempSync(
path.join(fs.realpathSync('/tmp'), 'gemini-cli-test-'),

This comment was marked as outdated.

const tempHomeDir = fs.mkdtempSync(
path.join(fs.realpathSync('/tmp'), 'gemini-cli-test-'),
);
process.env['GEMINI_CLI_HOME'] = tempHomeDir;

This comment was marked as outdated.

@gemini-cli gemini-cli Bot added priority/p2 Important but can be addressed in a future release. area/extensions Issues related to Gemini CLI extensions capability labels Jan 22, 2026
@spencer426 spencer426 force-pushed the feature/custom-themes branch from dd08323 to 5976610 Compare January 22, 2026 19:26
@github-actions

github-actions Bot commented Jan 22, 2026

Copy link
Copy Markdown

Size Change: +3.55 kB (+0.02%)

Total Size: 23.5 MB

Filename Size Change
./bundle/gemini.js 23.5 MB +3.55 kB (+0.02%)
ℹ️ 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

This change introduces the ability for extensions to define and register custom themes. Extensions can now include a  property in their  file, and these themes will be loaded and made available to the user.

Fixes #16192
@spencer426 spencer426 force-pushed the feature/custom-themes branch from 5976610 to dd57de4 Compare January 22, 2026 19:42
return a.label.localeCompare(b.label);
});
})
.sort((a, b) => {

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.

why did this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We are now merging built-in themes with extension-provided themes, the list is no longer guaranteed to be in order. This sort ensures alphabetical list regardless of the source.

return;
}

debugLogger.log(

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.

log this as debug or do not log. this is a bit spammy to log for all users.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, deleted.

this.activeTheme,
);
const isCustom =
[...this.settingsThemes.values()].includes(this.activeTheme) ||

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.

there are a bunch of dupe checks searching all 3 lists. please simplify by adding a helper that returns a list of all custom themes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, created a private _getAllCustomThemes() helper to consolidate custom themes.

overrides?: Record<string, AgentOverride>;
}

export interface CustomTheme {

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.

Is this now duplicated in package/cli and package/core? Please simplify so we only have one class defining a theme.
is there a reason this has to be in packages/core not packages/cli?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, removed the duplicate CustomTheme interface from packages/cli/src/ui/themes/theme.ts, redirecting all imports within packages/cli to @google/gemini-cli-core.

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.

Thanks for addressing this! Moving the CustomTheme interface to @google/gemini-cli-core and updating the imports in packages/cli is a great way to centralize the definition and avoid duplication. This improves maintainability and ensures a single source of truth for theme definitions across the project.

}
}

protected override async stopExtension(extension: GeminiCLIExtension) {

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.

please add a test verifying that stopping an extension with a theme causes the theme to change back to the default theme if that custom theme was in use.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a "Should revert to default theme when extension is stopped" spec in packages/cli/src/config/extension-manager-themes.spec.ts

@jacob314 jacob314 left a comment

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.

Done with a round of review comments. Overall looks promising!

@spencer426 spencer426 force-pushed the feature/custom-themes branch 2 times, most recently from b0baf23 to 1306f54 Compare January 23, 2026 02:19
@spencer426 spencer426 force-pushed the feature/custom-themes branch from 1306f54 to 92bad52 Compare January 23, 2026 02:25
@gemini-cli gemini-cli Bot added the help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! label Jan 23, 2026
@jw408

jw408 commented Jan 23, 2026

Copy link
Copy Markdown

@spencer426 CI is failing due to an unused import. I think the fix is to remove
GEMINI_MODEL_ALIAS_AUTO from line 16 of packages/cli/src/config/settingsSchema.ts

The test  in  was failing because the  provided to  was missing the  method.

This commit adds the missing  with a mocked  method to the  to correctly reflect the  interface expected by .
@spencer426 spencer426 force-pushed the feature/custom-themes branch from fafe035 to c9ec1c4 Compare January 23, 2026 16:24
@spencer426

Copy link
Copy Markdown
Contributor Author

@jw408 Thanks the issue with GEMINI_MODEL_ALIAS_AUTO has been resolved!

"version": "1.0.0",
"themes": [
{
"name": "My-Awesome-Theme",

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.

Can you make this theme reasonable. For example, do a shades of green theme where everything is green. Will be clearer than this one where all that changes is the primary color is different which is odd but not really recognizable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, I updated the example.

```

Alternatively, you can set it through the UI by running `gemini` and then
pressing `t`.

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.

this is not correct. pressing t does not change the theme. Please update to the correct shortcut.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread packages/cli/src/ui/themes/theme.ts Outdated

@jacob314 jacob314 left a comment

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.

Restarting extensions causes the current custom theme to be lost. You can reproduce by the theme stopping being purple after triggering a restart loading your example theme. Approved after that is resolved.

The other feedback is the custom themes don't seem consistent with the UI from the other themes. To remedy I would swap the order so "My Awesome Theme" shows up before the name of the extension it is from. E.g.
My Awesome theme (extension-name)
where extension name could be de-emphasized. That way they will read like other extensions but you can still see the source.

Image

Approved after these comments are addressed.

Addresses feedback on the custom themes feature:

- Fixes an issue where the active custom theme from an extension would be lost upon extension reload.  is now more resilient and re-finds themes by name after they are re-registered.

- Improves the display format of extension-provided themes in the theme selection dialog. The format is now  with the extension name de-emphasized, making it consistent with other UI elements.

- Updates the theme example to be more comprehensive ('shades of green') and corrects the instructions in the README, including the now-accurate  slash command.

- Removes unnecessary whitespace from the  interface in .
Addresses feedback on the custom themes feature:

- Fixes an issue where the active custom theme from an extension would be lost upon extension reload.  is now more resilient and re-finds themes by name after they are re-registered.

- Improves the display format of extension-provided themes in the theme selection dialog. The format is now  with the extension name de-emphasized, making it consistent with other UI elements.

- Updates the theme example to be more comprehensive ('shades of green') and corrects the instructions in the README, including the now-accurate  slash command.

- Removes unnecessary whitespace from the  interface in .
Corrected a flawed assertion in
that was checking for the default theme before the extension was disabled.
It now correctly checks for the extension theme's name, resolving the test failure.

This also includes the automatic update to NOTICES.txt due to preflight.
@spencer426

Copy link
Copy Markdown
Contributor Author

Restarting extensions causes the current custom theme to be lost. You can reproduce by the theme stopping being purple after triggering a restart loading your example theme. Approved after that is resolved.

The other feedback is the custom themes don't seem consistent with the UI from the other themes. To remedy I would swap the order so "My Awesome Theme" shows up before the name of the extension it is from. E.g. My Awesome theme (extension-name) where extension name could be de-emphasized. That way they will read like other extensions but you can still see the source.

Image Approved after these comments are addressed.

Updated and updated the pr to include the new example theme.

@jacob314 jacob314 left a comment

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.

lgtm

@spencer426 spencer426 added this pull request to the merge queue Jan 28, 2026
Merged via the queue into main with commit beaa134 Jan 28, 2026
25 checks passed
@spencer426 spencer426 deleted the feature/custom-themes branch January 28, 2026 19:10
sidwan02 pushed a commit to sidwan02/gemini-cli-gemma that referenced this pull request Feb 6, 2026
kuishou68 pushed a commit to iOfficeAI/gemini-cli-pro that referenced this pull request Feb 27, 2026
@sripasg sripasg added the size/l A large sized PR label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/extensions Issues related to Gemini CLI extensions capability help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p2 Important but can be addressed in a future release. size/l A large sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for custom themes in Extensions

4 participants