fix(hookify): drop hookify.* import prefix so hooks resolve in versioned cache#54429
Open
Codeturion wants to merge 1 commit intoanthropics:mainfrom
Open
fix(hookify): drop hookify.* import prefix so hooks resolve in versioned cache#54429Codeturion wants to merge 1 commit intoanthropics:mainfrom
Codeturion wants to merge 1 commit intoanthropics:mainfrom
Conversation
…ned cache Each hook script's sys.path setup added the parent of CLAUDE_PLUGIN_ROOT in the hope that Python would find a hookify package there. That works in dev mode (parent dir of plugins/hookify is plugins/, which literally contains hookify/ as a subdirectory) but fails in production where the cache layout puts the plugin at .../hookify/0.1.0/ — the parent dir contains only the version directory. All four hooks then fail import, emit a systemMessage, and exit 0; the plugin silently no-ops for every cache install. Drop the hookify. prefix from the imports across the four hook scripts and the core rule_engine module, and rely on the existing sys.path.insert(0, PLUGIN_ROOT) so that core, matchers, and utils resolve as top-level packages. The dead parent_dir block (which was the misleading mechanism) is removed and the comment updated. Closes anthropics#47868. Closes anthropics#33409.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hookify's four hook scripts and
core/rule_engine.pyusefrom hookify.core.Xandfrom hookify.Ximports. The plugin's source layout hascore/,matchers/,utils/as direct children of the plugin root with nohookify/wrapper directory, so these imports only resolve when something puts a literalhookifydirectory onsys.path. The hook scripts try to do this by adding the parent ofCLAUDE_PLUGIN_ROOTtosys.path. That coincidentally works in dev mode (whereparent(plugins/hookify) == plugins/, which contains ahookify/directory — the plugin root itself) but fails in the production cache layout (.../hookify/0.1.0/), where the parent contains only the version directory. All four hooks then fail import, emit{"systemMessage": "Hookify import error: No module named 'hookify'"}, and exit 0 — the plugin silently no-ops for every user with a cache install.Drop the
hookify.prefix from the 10 import statements and rely on the existingsys.path.insert(0, PLUGIN_ROOT)socore,matchers, andutilsresolve as top-level packages. Remove the misleadingparent_dirblock.Files changed
plugins/hookify/hooks/pretooluse.pyplugins/hookify/hooks/posttooluse.pyplugins/hookify/hooks/stop.pyplugins/hookify/hooks/userpromptsubmit.py— same edit in all four hook scripts: remove theparent_dirblock, simplify theif PLUGIN_ROOTguard, drophookify.from the two imports.plugins/hookify/core/rule_engine.py— drophookify.from the module-level import (line 10) and the__main__test import (line 278).Verification
Setup. Mirror the production cache layout the issues describe: copy the patched plugin tree to
notes/repro-hookify/cache/hookify/0.1.0/, then run each hook script withCLAUDE_PLUGIN_ROOTpointing at that path and a minimal validPreToolUseJSON payload on stdin. Run the same set against the dev layout (plugins/hookifydirectly) to check for regressions. Repro script:notes/repro-hookify/verify.sh.Details. Pre-fix runs were captured against
git show main:versions of the same five files; post-fix runs against this branch. Each hook either prints{"systemMessage": "Hookify import error: ..."}(broken) or{}(working — empty rule evaluation, since no.claude/hookify.*.local.mdfiles exist in the run cwd). Neither is exercised through the live Claude Code harness (no spacey-cache install available locally), but the harness invokes the hook scripts viapython3 <path>withCLAUDE_PLUGIN_ROOTset, which is exactly what the verification reproduces.Comparisons.
pretooluse.pyunder.../hookify/0.1.0/Hookify import error: No module named 'hookify', exit 0{}, exit 0posttooluse.pyunder.../hookify/0.1.0/{}, exit 0stop.pyunder.../hookify/0.1.0/{}, exit 0userpromptsubmit.pyunder.../hookify/0.1.0/{}, exit 0pretooluse.pyunderplugins/hookify/(dev layout, regression check){}, exit 0{}, exit 0posttooluse.py,stop.py,userpromptsubmit.pyunder dev layout{}, exit 0 each{}, exit 0 eachCLAUDE_PLUGIN_ROOTunsetHookify import error: No module named 'hookify', exit 0Hookify import error: No module named 'core', exit 0Regression notes.
rule_engine.py's__main__test path was never invokable via barepython3 core/rule_engine.pyfrom the plugin root (verified against upstreammain:ModuleNotFoundError: No module named 'hookify'). It requiredPYTHONPATH=plugins python3 plugins/hookify/core/rule_engine.pybefore, and works now viacd plugins/hookify && python3 -m core.rule_engine. Net brokenness is unchanged; the required incantation is updated. The graceful-degradation path (try/except ImportError → systemMessage → exit 0) is preserved end-to-end; only the error message text changes ('hookify'→'core'when imports legitimately can't resolve).Refs
Closes #47868
Closes #33409