Skip to content

fix(hookify): fall back to __file__ when CLAUDE_PLUGIN_ROOT is unset#1441

Closed
adelaidasofia wants to merge 1 commit intoanthropics:mainfrom
adelaidasofia:fix/hookify-plugin-root-fallback
Closed

fix(hookify): fall back to __file__ when CLAUDE_PLUGIN_ROOT is unset#1441
adelaidasofia wants to merge 1 commit intoanthropics:mainfrom
adelaidasofia:fix/hookify-plugin-root-fallback

Conversation

@adelaidasofia
Copy link
Copy Markdown

Problem

The four hook scripts in plugins/hookify/hooks/ depend on CLAUDE_PLUGIN_ROOT to add the plugin directory to sys.path so they can import core.config_loader and core.rule_engine:

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

try:
    from core.config_loader import load_rules
    from core.rule_engine import RuleEngine
except ImportError as e:
    error_msg = {"systemMessage": f"Hookify import error: {e}"}
    print(json.dumps(error_msg), file=sys.stdout)
    sys.exit(0)

In some contexts Claude Code does not set CLAUDE_PLUGIN_ROOT on the subprocess it spawns for the hook. When that happens the imports fail, the script emits a systemMessage, and PreToolUse defaults to BLOCK, silently blocking every Write, Edit, and Bash call for the session.

I hit this reliably in git worktree sessions and some subagent contexts. The error the user sees is:

Hookify's own import is broken (No module named 'core'), which Claude Code treats as a block.

Even with sys.exit(0), the non-empty systemMessage and failed import are enough for the host to treat the PreToolUse hook as failed.

Fix

Since the script already knows its own location, it can derive the plugin root from __file__ as a fallback. The env-var path still takes precedence, so existing behavior is preserved.

PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT') or os.path.dirname(
    os.path.dirname(os.path.abspath(__file__))
)
if PLUGIN_ROOT not in sys.path:
    sys.path.insert(0, PLUGIN_ROOT)

Same pattern applied to all four hook scripts (pretooluse.py, posttooluse.py, stop.py, userpromptsubmit.py).

Verification

All four scripts return {} and exit 0 when piped stdin input with CLAUDE_PLUGIN_ROOT unset:

$ for f in pretooluse posttooluse stop userpromptsubmit; do
    echo '{"tool_name":"Write","tool_input":{}}' | python3 plugins/hookify/hooks/$f.py
  done
{}
{}
{}
{}

Before the patch the same commands produced {"systemMessage": "Hookify import error: No module named 'core'"}.

Hook scripts depend on CLAUDE_PLUGIN_ROOT to add the plugin directory to
sys.path so they can import core.config_loader and core.rule_engine. In
some Claude Code contexts (observed in git worktrees and certain subagent
subprocesses) the env var is not set on the spawned hook process. When
that happens the imports fail, the script emits a systemMessage, and
PreToolUse defaults to BLOCK, silently blocking every Write, Edit, and
Bash call for the session.

Since the script already knows its own location, it can derive the plugin
root from __file__ as a fallback. This preserves the existing env-var
path, adds no runtime cost, and makes the hooks robust to any spawning
context.

Verified: all four hook scripts now return an empty JSON object and exit 0
when piped stdin input with CLAUDE_PLUGIN_ROOT unset.
@github-actions
Copy link
Copy Markdown

Thanks for your interest! This repo only accepts contributions from Anthropic team members. If you'd like to submit a plugin to the marketplace, please submit your plugin here.

@github-actions github-actions Bot closed this Apr 16, 2026
adelaidasofia added a commit to adelaidasofia/ai-brain-starter that referenced this pull request Apr 16, 2026
The links pointed to anthropics/claude-code/tree/main/plugins/hookify.
The hookify plugin actually lives in the separate marketplace repo
anthropics/claude-plugins-official. Both references updated.

Found while filing anthropics/claude-plugins-official#1441 (unrelated
CLAUDE_PLUGIN_ROOT fallback fix in hookify itself).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant