Skip to content

[BUG] hookify plugin: 'No module named hookify' on every hook event when installed from marketplace #69665

Description

@kubiknyc

Summary

The hookify plugin (plugins/hookify/) fails to import its own engine on every hook invocation when installed via the marketplace. Each PreToolUse/PostToolUse/Stop/UserPromptSubmit event emits:

Hookify import error: No module named 'hookify'

Because the hook scripts catch the ImportError and sys.exit(0), the failure is non-fatal but silent: no user rule is ever evaluated, so the plugin is effectively inert while spamming this systemMessage.

  • Plugin version: 0.1.0
  • Installed commit: ca9f6045fc90c8244f9e787fb57d54b380f9a27c
  • Platform: Windows 11, Python 3.13
  • Install path: ~/.claude/plugins/cache/claude-code-plugins/hookify/0.1.0/

Root cause

The hook entry scripts (hooks/pretooluse.py etc.) and core/rule_engine.py import via the top-level package name:

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

To make that resolve, hooks/*.py add os.path.dirname(CLAUDE_PLUGIN_ROOT) to sys.path, assuming the plugin directory is literally named hookify (true in-repo: plugins/hookify/). But the marketplace installer places the plugin under a version directory:

.../claude-code-plugins/hookify/0.1.0/    <- CLAUDE_PLUGIN_ROOT
        core/  hooks/  matchers/  utils/   <- no top-level `hookify` package

So dirname(CLAUDE_PLUGIN_ROOT) is .../hookify (the version container), not a directory that contains an importable hookify package. import hookify therefore fails, and so does every hookify.core.* import — including the cross-import inside core/rule_engine.py.

Reproduction

cd ~/.claude/plugins/cache/claude-code-plugins/hookify/0.1.0
CLAUDE_PLUGIN_ROOT="$(pwd)" echo '{}' | python3 hooks/pretooluse.py
# => {"systemMessage": "Hookify import error: No module named 'hookify'"}

Suggested fixes (any one)

  1. Make imports root-relative. Since hooks/*.py already add CLAUDE_PLUGIN_ROOT to sys.path, change from hookify.core.X -> from core.X in the 4 hook scripts and in core/rule_engine.py (lines importing hookify.core.config_loader). Self-contained, no path assumptions.

  2. Ship a package marker. Add plugins/hookify/__init__.py and have the installer preserve a hookify-named package dir, so import hookify resolves regardless of the version-dir layout.

  3. Don't assume the plugin dir name. The sys.path bootstrap in hooks/*.py hardcodes the assumption that the plugin folder is named hookify; make the engine importable by relative path instead.

Workaround (for affected users)

Drop a one-file shim that re-points a hookify package at the plugin root (the scripts already put the root on sys.path):

# .../hookify/0.1.0/hookify/__init__.py
import os
_PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _PLUGIN_ROOT not in __path__:
    __path__.append(_PLUGIN_ROOT)

After this, all four hooks load and rules evaluate correctly. (Lost on plugin reinstall/update.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions