[BUG] Disabled plugin's PostToolUse hook still executes on every Edit/Write despite not being listed in /hooks
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Setting a plugin to false under enabledPlugins in ~/.claude/settings.json unloads that plugin's skills and agents but does not unregister its PostToolUse hook. The hook continues executing on every Edit and Write, creating directories inside unrelated project repositories. No settings file enables the plugin — the only reference anywhere is the false.
The disable is applied inconsistently: the plugin's skill and its agent both disappear from the session, which makes the still-running hook harder to notice. The hooks UI lists no PostToolUse entry, so nothing in the interface indicates any PostToolUse hook is active. Yet the hook still runs.
What Should Happen?
A plugin disabled via enabledPlugins should contribute nothing to the session. No skills, no agents, and no hooks. "Disabled" should mean "not running."
More importantly, the hooks listing must be complete and authoritative: any hook that executes must appear in /hooks, and a hook absent from /hooks must never run. Whatever the cause, a session silently executing third-party code on every file edit while the interface reports no such hook is the more serious defect.
Error Messages/Logs
No errors. The failure is silent. Observable side effect only:
$ # with "impeccable@impeccable": false in ~/.claude/settings.json
$ # perform any Write via Claude Code, then:
$ find . -name ".impeccable"
./.impeccable # contains hook.cache.json
Plugin's hook definition (~/.claude/plugins/cache/impeccable/impeccable/3.6.0/hooks/hooks.json):
PostToolUse | matcher: Edit|Write|MultiEdit
node "${CLAUDE_PLUGIN_ROOT}/skills/impeccable/scripts/hook.mjs"
Plugin remains installed despite being disabled (~/.claude/plugins/installed_plugins.json):
{ "version": 2, "plugins": { "impeccable@impeccable": [
{ "scope": "user", "version": "3.6.0",
"installPath": "/Users/<me>/.claude/plugins/cache/impeccable/impeccable/3.6.0" } ] } }
Steps to Reproduce
- Install a plugin that registers a PostToolUse hook on Edit|Write|MultiEdit. Reproduced with impeccable@impeccable 3.6.0 from marketplace pbakaus/impeccable.
- Confirm the hook fires: perform any Write, observe .impeccable/hook.cache.json created beside the written file.
- Set "enabledPlugins": { "impeccable@impeccable": false } in ~/.claude/settings.json.
- Fully quit and relaunch Claude Code.
- Confirm the disable partially applied — the plugin's skill and its agent are both absent from the session's available listings.
- Verify no other settings file re-enables it (grep -rn impeccable ~/.claude/settings.json .claude/settings*.json) — the only match is the false.
- Perform any Write.
- A .impeccable/ directory is created again. The hook is still running.
Only claude plugin uninstall impeccable@impeccable stops it.
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.227 (Claude Code)
Platform
Other
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
Hook registration appears keyed to installed state (installed_plugins.json) rather than to enabledPlugins, which would explain why skills and agents honor the flag and hooks do not.
This is a trust-boundary issue. A plugin the user believes is disabled keeps executing third-party code on every file edit and writing into their repositories. Not a vulnerability in the strict sense (the user installed and previously enabled it) but users reasonably read "disabled" as "not running," and if the hooks UI shows nothing, there is no surfaced signal that it still runs.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗