Summary
The hookify feature ships the authoring half but not the execution half. /hookify generates rule files at .claude/hookify.<name>.local.md, and /hookify-configure lets you flip their enabled: field — but nothing in ECC ever reads or evaluates those files. Every rule created via /hookify is inert. It silently does nothing while giving the user the impression that a guardrail is now in place.
Environment
- ECC version: 2.0.0 (installed via the Claude Code plugin marketplace)
- Mechanism: Claude Code plugin
hooks.json
Evidence
In the installed ECC plugin, hooks/ contains only:
hooks/
memory-persistence/
README.md
hooks.json
There is no pretooluse / posttooluse / stop / userpromptsubmit handler, and no core/ (rule engine / config loader) or matchers/ directory anywhere in the plugin. Grepping the whole plugin outside commands/, skills/, and docs/ finds nothing that reads .claude/hookify.*.local.md: the string hookify appears only in command/skill/doc markdown, never in hooks/ or scripts/. hooks/hooks.json registers no handler that loads these rule files.
By contrast, Anthropic's official hookify plugin — which uses the identical .local.md rule format — ships the complete runtime:
hooks/pretooluse.py
hooks/posttooluse.py
hooks/stop.py
hooks/userpromptsubmit.py
hooks/hooks.json # registers the 4 handlers, one per event
core/rule_engine.py
core/config_loader.py
matchers/
Its hooks/hooks.json wires each event to python3 "${CLAUDE_PLUGIN_ROOT}/hooks/<event>.py", which load and evaluate the rules. ECC has none of this.
Because the official plugin works on the same Claude Code hook mechanism, this is not a Claude Code regression — the hook API is intact. The runtime is simply absent from ECC's packaging.
Secondary issue: action: warn would be silent even if a runtime existed
Even with a dispatcher, the default action: warn maps to a hook exit code of 0. Under Claude Code's hook contract, only a non-zero blocking exit (exit 2) feeds the hook's stderr back into the model's context; exit 0 is invisible to the model. So warn rules would never surface to Claude regardless. A working implementation needs to emit the message via exit 2 (or the additionalContext field) for it to reach the agent.
Steps to reproduce
/hookify <some behavior to prevent> → it creates .claude/hookify.<name>.local.md.
- Perform the action the rule is meant to warn about / block.
- Observe: nothing happens. The rule never fires.
/hookify-configure shows it as enabled, but toggling enabled: changes nothing because no code reads the field.
Expected vs. actual
- Expected: rules created by
/hookify are read and enforced (warn/block), consistent with the command's stated purpose — "Create hooks to prevent unwanted behaviors" — and with /hookify-configure — "Enable or disable hookify rules".
- Actual: the rule files are never read; they enforce nothing.
Suggested fixes (any one addresses the core problem)
- Ship the runtime — port the official plugin's
hooks/*.py + core/ + matchers/ (or an ECC-native equivalent) and register the per-event handlers in hooks/hooks.json.
- If ECC intends users to rely on the official hookify plugin (or native hooks) for enforcement, document that dependency explicitly and make
/hookify / /hookify-configure state that the generated files require that separate runtime to have any effect.
- Ensure
action: warn actually reaches the model (exit 2 with a clear message, or additionalContext), so warnings are not silently dropped.
Why this matters
The failure mode is not "junk files" — it is a false sense of safety. A user writes a rule to stop a recurring mistake, believes they are now protected, and the mistake recurs unguarded. Since the rule files are typically git-ignored, they never reach commit-time checks either, so nothing else catches the gap. Please either wire up enforcement or make the runtime requirement explicit in the docs.
Filed after diagnosing why /hookify-generated rules had no effect in a real project. Happy to provide additional detail or test a fix.
Summary
The
hookifyfeature ships the authoring half but not the execution half./hookifygenerates rule files at.claude/hookify.<name>.local.md, and/hookify-configurelets you flip theirenabled:field — but nothing in ECC ever reads or evaluates those files. Every rule created via/hookifyis inert. It silently does nothing while giving the user the impression that a guardrail is now in place.Environment
hooks.jsonEvidence
In the installed ECC plugin,
hooks/contains only:There is no
pretooluse/posttooluse/stop/userpromptsubmithandler, and nocore/(rule engine / config loader) ormatchers/directory anywhere in the plugin. Grepping the whole plugin outsidecommands/,skills/, anddocs/finds nothing that reads.claude/hookify.*.local.md: the stringhookifyappears only in command/skill/doc markdown, never inhooks/orscripts/.hooks/hooks.jsonregisters no handler that loads these rule files.By contrast, Anthropic's official
hookifyplugin — which uses the identical.local.mdrule format — ships the complete runtime:Its
hooks/hooks.jsonwires each event topython3 "${CLAUDE_PLUGIN_ROOT}/hooks/<event>.py", which load and evaluate the rules. ECC has none of this.Because the official plugin works on the same Claude Code hook mechanism, this is not a Claude Code regression — the hook API is intact. The runtime is simply absent from ECC's packaging.
Secondary issue:
action: warnwould be silent even if a runtime existedEven with a dispatcher, the default
action: warnmaps to a hook exit code of0. Under Claude Code's hook contract, only a non-zero blocking exit (exit 2) feeds the hook's stderr back into the model's context;exit 0is invisible to the model. Sowarnrules would never surface to Claude regardless. A working implementation needs to emit the message viaexit 2(or theadditionalContextfield) for it to reach the agent.Steps to reproduce
/hookify <some behavior to prevent>→ it creates.claude/hookify.<name>.local.md./hookify-configureshows it asenabled, but togglingenabled:changes nothing because no code reads the field.Expected vs. actual
/hookifyare read and enforced (warn/block), consistent with the command's stated purpose — "Create hooks to prevent unwanted behaviors" — and with/hookify-configure— "Enable or disable hookify rules".Suggested fixes (any one addresses the core problem)
hooks/*.py+core/+matchers/(or an ECC-native equivalent) and register the per-event handlers inhooks/hooks.json./hookify//hookify-configurestate that the generated files require that separate runtime to have any effect.action: warnactually reaches the model (exit 2with a clear message, oradditionalContext), so warnings are not silently dropped.Why this matters
The failure mode is not "junk files" — it is a false sense of safety. A user writes a rule to stop a recurring mistake, believes they are now protected, and the mistake recurs unguarded. Since the rule files are typically git-ignored, they never reach commit-time checks either, so nothing else catches the gap. Please either wire up enforcement or make the runtime requirement explicit in the docs.
Filed after diagnosing why
/hookify-generated rules had no effect in a real project. Happy to provide additional detail or test a fix.