Problem
skills/hook-kit/resources/block-taskcreate-error-unretried.sh is an unconditional delegator:
PY="$(command -v python3 || true)"
[ -z "$PY" ] && exit 0
exec "$PY" "$(dirname "$0")/block-taskcreate-error-unretried.py"
The sibling .py file it execs is not present anywhere in this repository's git history — it was authored (or later migrated) into a separate, non-published personal skill instead. On any environment where python3 is on PATH (the common case), the exec target does not exist, so the process fails immediately with a nonzero exit on every tool call the hook is wired to.
hooks/hooks.json currently wires this .sh to the PreToolUse matchers for Edit, Write, and Bash (three separate registrations). Since none of those tool calls can succeed while the guard crashes, this silently blocks essentially all mutating tool use in any session that has this hook active and does not already have a local workaround file in place. The only reason this has not been fully disruptive is an ad-hoc no-op stub (sys.exit(0)) manually placed at the expected .py path outside of any commit — which defeats the guard's actual purpose (enforcing that a failed TaskCreate call gets retried before further work proceeds) without anyone deciding that on purpose.
Scope
- Decide whether
block-taskcreate-error-unretried's guard logic (detect an errored TaskCreate tool_use with no successful retry since, block Edit/Write/Bash until retried) belongs in the published hook-kit skill or should stay a personal-only hook:
- If it belongs in
hook-kit: commit the real .py implementation alongside the existing .sh wrapper so a fresh install actually has both files.
- If it should stay personal-only: remove the three
hooks.json registrations (and the now-orphaned .sh wrapper) from hook-kit entirely, so the public plugin does not reference resources it does not ship.
- Add a lint/self-test check (e.g. extending the existing hook-kit fixture suite or a
hooks.json sanity check) that fails when a hooks.json command references a script file that is not present/tracked in the same skill's resources/ directory — this class of drift (a hook wired up in hooks.json with its implementation file missing) should be caught before install rather than discovered as a live crash.
Verification
| Feature |
Procedure |
Expected Result |
| Guard resolves on fresh install |
Install/mirror hook-kit from a clean checkout (no manually-placed stub files) and trigger an Edit/Write/Bash call |
Hook runs its real logic (allow or block based on TaskCreate retry state) instead of crashing |
No dangling hooks.json reference |
Run the new lint/self-test check against hooks.json |
0 references to script files missing from their skill's resources/ directory |
| Existing hook fixtures |
Run the hook-kit self-test suite |
All existing tests still pass |
Problem
skills/hook-kit/resources/block-taskcreate-error-unretried.shis an unconditional delegator:The sibling
.pyfile itexecs is not present anywhere in this repository's git history — it was authored (or later migrated) into a separate, non-published personal skill instead. On any environment wherepython3is onPATH(the common case), theexectarget does not exist, so the process fails immediately with a nonzero exit on every tool call the hook is wired to.hooks/hooks.jsoncurrently wires this.shto thePreToolUsematchers forEdit,Write, andBash(three separate registrations). Since none of those tool calls can succeed while the guard crashes, this silently blocks essentially all mutating tool use in any session that has this hook active and does not already have a local workaround file in place. The only reason this has not been fully disruptive is an ad-hoc no-op stub (sys.exit(0)) manually placed at the expected.pypath outside of any commit — which defeats the guard's actual purpose (enforcing that a failedTaskCreatecall gets retried before further work proceeds) without anyone deciding that on purpose.Scope
block-taskcreate-error-unretried's guard logic (detect an erroredTaskCreatetool_use with no successful retry since, blockEdit/Write/Bashuntil retried) belongs in the publishedhook-kitskill or should stay a personal-only hook:hook-kit: commit the real.pyimplementation alongside the existing.shwrapper so a fresh install actually has both files.hooks.jsonregistrations (and the now-orphaned.shwrapper) fromhook-kitentirely, so the public plugin does not reference resources it does not ship.hooks.jsonsanity check) that fails when ahooks.jsoncommand references a script file that is not present/tracked in the same skill'sresources/directory — this class of drift (a hook wired up inhooks.jsonwith its implementation file missing) should be caught before install rather than discovered as a live crash.Verification
hook-kitfrom a clean checkout (no manually-placed stub files) and trigger anEdit/Write/Bashcallhooks.jsonreferencehooks.jsonresources/directory