Feature request: per-plugin hook disable (keep skills/commands, opt out of hooks)
Summary
When a user installs a plugin from a marketplace, they get all of its components — skills, slash commands, agents, and hooks — as a bundle. There's no documented way to opt out of just the hooks while keeping the rest of the plugin enabled. Today the only documented options are:
- Disable the entire plugin via
/plugin disable <plugin>@<marketplace>(loses skills + commands too) - Set
disableAllHooks: true(turns off every hook from every plugin, plus any user-defined ones) - Fork the plugin and remove
hooks/from the fork
A per-plugin or per-hook disable would let users keep the parts of a plugin they want and opt out of the parts they don't.
Concrete use case
A plugin ships:
- A skill describing how to compose a git commit message — useful, want to keep.
- A PreToolUse hook on
Bash(git commit *)that gates commits on the skill having been invoked — useful in some workflows, annoying in others (e.g. when the user is also running another commit-related slash-command plugin and doesn't want the two interacting).
The user wants the skill loaded and discoverable via /<skill-name> slash invocations. They don't want the hook firing on every git commit. Today, the only way to get that is to fork the plugin and strip its hooks/ directory before installing — which means losing automatic updates and turning a marketplace consumer into a maintainer.
The same shape applies to:
- A plugin that ships both a security review skill and a hook that blocks
gh pr createuntil the skill has been read. - A plugin that ships both a database migration skill and a hook that runs lint checks on every
git commit. - Any plugin where the hook is one of multiple components and a user wants the others without the hook.
What's been tried
/plugin disable— too coarse. Disables skills and commands too.disableAllHooks: true— too coarse and too surprising. Disables every plugin's hooks, plus the user's own hooks, often as a side effect of trying to opt out of just one.- Editing files under
~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/hooks/hooks.json— not durable. The cache is regenerated on/plugin marketplace updateand/plugin install. Any edits get clobbered. - Forking the plugin — works, but turns every marketplace consumer into a maintainer.
Proposed shapes
Any of these would address it; they're listed in increasing scope.
- Per-plugin hook disable — settings.json field that disables all hooks from a specific plugin while keeping the plugin's skills and commands enabled:
``json``
{
"pluginOverrides": {
"<plugin>@<marketplace>": {
"disableHooks": true
}
}
}
- Per-event-type hook disable — disable a plugin's PreToolUse hooks but leave its SessionStart hooks alone (for example):
``json``
{
"pluginOverrides": {
"<plugin>@<marketplace>": {
"disabledHookEvents": ["PreToolUse"]
}
}
}
- Per-named-hook disable — most granular. Requires hooks to be named in the plugin's
hooks.json, then referenced by name in user settings:
``json``
{
"pluginOverrides": {
"<plugin>@<marketplace>": {
"disabledHooks": ["check-commit-craft"]
}
}
}
(1) covers most real use cases and is the simplest to implement. (3) is the cleanest end state but requires a hook-naming convention the schema doesn't currently enforce.
A /plugin slash-command equivalent (e.g. /plugin disable-hooks <plugin>@<marketplace>) would make this discoverable without users having to know the settings.json schema.
Persistence requirements
The disable setting needs to live in ~/.claude/settings.json (or its project/local siblings), not in the plugin cache, and must survive /plugin marketplace update and /plugin install. The same persistence model enabledPlugins already uses for the whole-plugin disable case is the obvious template.
Honest limitations
Hooks are part of a plugin's design — disabling them silently can change the plugin's intended behavior. The setting should be:
- Opt-in (no default disabling)
- Visible (e.g.
/plugin info <plugin>should surface that some of its hooks are disabled in the current session) - Logged when a hook would have fired but didn't, so users debugging behavior can correlate
Adjacent existing requests
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗