Skip to content

Conversation

@AbdulTawabJuly
Copy link

@AbdulTawabJuly AbdulTawabJuly commented Dec 27, 2025

Summary

Implements granular extension hook control, allowing users to disable all hooks from specific extensions while keeping other extension features (like MCP tools) operational.

Details

What's New

  • Per-extension hook disabling: Users can now disable all hooks from a specific extension using the setting hooks.extensionHooksDisabled: ["extension-name"] or via the /hooks command with wildcard syntax extension/*.
  • Clear UI attribution: Extension hooks are labeled with their source extension (🔌 icon) in the hook list for better transparency.
  • Independent functionality: Disabling an extension's hooks does not affect its MCP tools, prompts, resources, or other features.

Changes Made

  • hookRegistry.ts: Added extensionName tracking to hook entries and setExtensionHooksEnabled() method for runtime control.
  • hookSystem.ts: Added wrapper to expose setExtensionHooksEnabled() for public use.
  • config.ts:
    • Added getExtensionHooksDisabled() method and extensionHooksDisabled field.
    • Fixed getHooks() and getProjectHooks() to filter out config properties (disabled, extensionHooksDisabled) so only valid HookEventName enum values are processed.
    • Prevents "Invalid hook event name" warnings and ensures disabled hooks don't execute.

Related Issues

Fixes #15263

How to Validate

I created demo extensions with hooks and MCP tools since no existing extensions combine all three features.
To validate:

  • Run /hooks to view all registered hooks with their source extension labeled.
  • Disable demo-extension hooks via /hooks disable extension/demo-extension.
  • Run /hooks again to confirm the hooks are marked as disabled and produce no output.
  • Test MCP tools before and after disabling.

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

@AbdulTawabJuly AbdulTawabJuly requested a review from a team as a code owner December 27, 2025 18:19
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @AbdulTawabJuly, 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 hook system, providing granular control over extension-contributed hooks. Users can now disable all hooks from a specific extension via a new configuration setting or an updated CLI command, without affecting other functionalities of that extension. This change improves user control and transparency by clearly labeling extension hooks in the UI and preventing 'Invalid hook event name' warnings by filtering configuration properties.

Highlights

  • Granular Extension Hook Control: Introduced the ability to disable all hooks from a specific extension while keeping other extension features (like MCP tools) operational.
  • New Configuration Setting: Added a new setting hooks.extensionHooksDisabled (an array of strings) to specify extension names whose hooks should be disabled.
  • CLI Command Enhancements: The /hooks command now supports wildcard syntax (extension/*) for enabling or disabling all hooks associated with a particular extension.
  • Improved UI Transparency: The hook list UI now clearly attributes extension hooks with their source extension, including a '📦' icon for better visual identification.
  • Independent Functionality: Disabling an extension's hooks does not impact its other features like MCP tools, prompts, or resources, ensuring modular control.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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.

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 granular control over extension hooks, allowing users to disable all hooks from a specific extension. The changes include a new setting, updates to the /hooks command to support extension-based enable/disable actions, and UI improvements to show hook sources. The implementation is solid and includes good test coverage. However, I've found a high-severity issue where enabling an extension's hooks can lead to an inconsistent state for individually disabled hooks, which I've detailed in a comment.

let count = 0;
for (const entry of this.entries) {
if (entry.extensionName === extensionName) {
entry.enabled = enabled;
Copy link
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 setExtensionHooksEnabled can lead to an inconsistent state between the in-memory representation of enabled hooks and the state that would be loaded from settings on a restart.

When enabling all hooks for an extension (enabled: true), this function sets entry.enabled = true for all hooks from that extension. This overrides any individual hooks that are explicitly disabled in the hooks.disabled setting.

However, upon application restart, HookRegistry.initialize() will re-process the settings. processHookDefinition correctly considers both disabledHooks and extensionHooksDisabled. A hook that is in disabledHooks will be correctly marked as enabled: false, even if its extension is not in extensionHooksDisabled.

This means a hook that was individually disabled, then enabled as part of its extension, will be enabled for the current session but disabled again after a restart. This is unpredictable behavior for the user.

To fix this, setExtensionHooksEnabled should respect the disabledHooks setting when enabling hooks.

A similar issue exists in the setHookEnabled method, which is not part of this pull request but should be updated to respect extensionHooksDisabled for consistency.

Suggested change
entry.enabled = enabled;
entry.enabled = enabled && !(this.config.getDisabledHooks() || []).includes(this.getHookName(entry));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Granular Extension Hook Control

1 participant