Bug: Hookify plugin Python import error in cache directory structure

Resolved 💬 4 comments Opened Dec 19, 2025 by chinlung Closed Dec 22, 2025

Bug Description

The hookify plugin fails with No module named 'hookify' error when running hook scripts. This affects all hook events (PreToolUse, PostToolUse, UserPromptSubmit, Stop).

Error Message

Hookify import error: No module named 'hookify'

Root Cause

The Python hook scripts use import statements like:

from hookify.core.config_loader import load_rules
from hookify.core.rule_engine import RuleEngine

The scripts attempt to add parent_dir (parent of CLAUDE_PLUGIN_ROOT) to sys.path:

PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT')  # e.g., .../hookify/0.1.0
parent_dir = os.path.dirname(PLUGIN_ROOT)            # e.g., .../hookify
sys.path.insert(0, parent_dir)

The Problem:

  • Cache directory structure: .../cache/claude-code-plugins/hookify/0.1.0/core/
  • Python expects: .../cache/claude-code-plugins/hookify/hookify/core/

The cache system uses the version number (0.1.0) as the directory name, not the plugin name (hookify). So when Python tries to import hookify.core.xxx, it looks for a hookify/ subdirectory under parent_dir, but finds 0.1.0/ instead.

Marketplace version works because the structure is:
.../plugins/hookify/core/ ← matches expected import path

Workaround

Create a symlink in the cache directory:

cd /Users/<user>/.claude/plugins/cache/claude-code-plugins/hookify
ln -sf 0.1.0 hookify

Suggested Fix

Modify the hook Python scripts to use the correct import path based on actual directory structure. Options:

Option 1: Direct import from PLUGIN_ROOT

PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT')
if PLUGIN_ROOT and PLUGIN_ROOT not in sys.path:
    sys.path.insert(0, PLUGIN_ROOT)

from core.config_loader import load_rules
from core.rule_engine import RuleEngine

Option 2: Dynamic package resolution

PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT')
if PLUGIN_ROOT:
    # Create hookify as module alias pointing to PLUGIN_ROOT
    parent_dir = os.path.dirname(PLUGIN_ROOT)
    plugin_name = os.path.basename(os.path.dirname(parent_dir))  # Get actual plugin name
    # ... handle import dynamically

Environment

  • macOS (Darwin 25.2.0)
  • Python 3.x
  • Claude Code with plugins from marketplace

Affected Files

  • hooks/userpromptsubmit.py
  • hooks/pretooluse.py
  • hooks/posttooluse.py
  • hooks/stop.py

All four hook scripts have the same import pattern issue.

View original on GitHub ↗

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