Hookify plugin: 'stop' event rules incorrectly fire on all tool uses
Problem
The hookify plugin's event: stop rules are incorrectly firing on every tool use (Read, Grep, Glob, etc.) instead of only firing when the main agent stops.
Evidence
When a hookify rule is configured with event: stop:
---
name: require-tests-before-stopping
enabled: true
event: stop
action: warn
conditions:
- field: reason
operator: regex_match
pattern: .*
---
⚠️ **Test Verification Required**
...
The rule fires on PreToolUse and PostToolUse hooks for ALL tools:
Read(.claude/hookify.prevent-commenting-tests.local.md)
⎿ PreToolUse:Read says: **[require-tests-before-stopping]**
⚠️ **Test Verification Required**
...
⎿ PostToolUse:Read says: **[require-tests-before-stopping]**
⚠️ **Test Verification Required**
...
Root Cause
In hooks/pretooluse.py and hooks/posttooluse.py, when processing tools other than Bash/Edit/Write/MultiEdit, the code sets event=None:
tool_name = input_data.get('tool_name', '')
event = None
if tool_name == 'Bash':
event = 'bash'
elif tool_name in ['Edit', 'Write', 'MultiEdit']:
event = 'file'
# Load rules
rules = load_rules(event=event) # ← Passing event=None!
When event=None, the filtering logic in core/config_loader.py doesn't run:
# Filter by event if specified
if event: # ← This is False when event=None!
if rule.event != 'all' and rule.event != event:
continue
This causes all rules (including event: stop rules) to be loaded and evaluated for tools like Read, Grep, Glob.
Impact
event: stoprules spam warnings/blocks on every tool use- Users cannot create reliable "before stopping" checks
- Hookify rules become unusable for completion verification workflows
- Significant noise in the UI during normal operations
Steps to Reproduce
- Create
.claude/hookify.test-stop.local.md:
---
name: test-stop-event
enabled: true
event: stop
action: warn
---
This should only appear on Stop events!
- Use any non-bash/non-file tool (Read, Grep, Glob)
- Observe the warning appears on PreToolUse and PostToolUse hooks
Fix
Add early exit in pretooluse.py and posttooluse.py when tool is not bash/file-related:
event = None
if tool_name == 'Bash':
event = 'bash'
elif tool_name in ['Edit', 'Write', 'MultiEdit']:
event = 'file'
else:
# No relevant event for this tool - exit early
# This prevents loading 'stop' and other non-tool-specific rules
print(json.dumps({}), file=sys.stdout)
sys.exit(0)
# Load rules
rules = load_rules(event=event)
This ensures that only bash and file rules are processed in PreToolUse/PostToolUse hooks, while stop rules are only processed by the dedicated stop.py hook.
Environment
- Claude Code version: Latest
- Hookify plugin version: 0.1.0
- Platform: macOS (but affects all platforms)
Labels
- bug
- plugin
- hookify
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗