Bug: hookify stop/prompt rules never match due to wrong field mapping in config_loader.py

Resolved 💬 4 comments Opened Mar 8, 2026 by istarwyh Closed Apr 7, 2026

Bug Description

Hookify rules with event: stop or event: prompt using the simple pattern syntax never match, because config_loader.py maps them to field=content, which rule_engine.py cannot extract for Stop/UserPromptSubmit events.

Steps to Reproduce

  1. Create a hookify rule file .claude/hookify.test-stop.local.md:
---
name: test-stop
enabled: true
event: stop
pattern: .*
action: warn
---

This should trigger on every stop event.
  1. The rule will never fire, because:
  • config_loader.py:from_dict() converts event=stop + pattern=.* into Condition(field='content', ...)
  • rule_engine.py:_extract_field() returns None for field='content' on Stop events (no tool_input, no special case handling)
  • Since the field value is None, the condition always fails

Root Cause

In core/config_loader.py, the Rule.from_dict() method (line ~61):

event = frontmatter.get('event', 'all')
if event == 'bash':
    field = 'command'
elif event == 'file':
    field = 'new_text'
else:
    field = 'content'  # <-- stop and prompt events fall here

The else branch maps both stop and prompt events to field='content', but rule_engine.py:_extract_field() has no handler for content on Stop events — it only handles reason and transcript.

Fix

event = frontmatter.get('event', 'all')
if event == 'bash':
    field = 'command'
elif event == 'file':
    field = 'new_text'
elif event == 'stop':
    field = 'reason'
elif event == 'prompt':
    field = 'user_prompt'
else:
    field = 'content'

This maps:

  • stop events → field='reason' (which _extract_field already supports via input_data.get('reason', ''))
  • prompt events → field='user_prompt' (which _extract_field already supports via input_data.get('user_prompt', ''))

Verification

Before fix:

$ echo '{"hook_event_name":"Stop","reason":"task completed"}' | python3 hooks/stop.py
{}

After fix:

$ echo '{"hook_event_name":"Stop","reason":"task completed"}' | python3 hooks/stop.py
{"systemMessage": "**[test-stop]**\nThis should trigger on every stop event."}

Environment

  • Plugin version: hookify 0.1.0
  • Source: plugins/hookify/core/config_loader.py

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗