Primarily a bug-fix release. The two additions exist because fixing the bug
properly required a discovery implementation you can actually run and inspect.
Fixed
- Hooks silently failing to run (#4). Hook discovery was described in
HOOKS.mdas prose steps for the model to follow, so every session improvised its own bash enumeration. One such script hit a parse error partway through (for f in $LOC/*.md 2>/dev/null— redirections aren't allowed in aforword list), its partial output was consumed as a complete enumeration, and every hook resolved empty. Nothing surfaced, because the empty-hook rule mandates silence — a crashed discovery and a legitimately empty one were indistinguishable. Discovery is now a shipped script (hooks/discover-hooks.sh) that both skills run at all 8 call sites. - The frontmatter example in our own docs didn't parse.
HOOKS.mdandREADME.mdboth document enrollment with a trailing comment on every value (phase: post-plan # enrolls this agent…). That form yielded an unknown phase and a non-numeric order, so anyone copy-pasting the documented example got an agent that never ran. - Agent files with CRLF line endings were silently skipped, since
---\rdoesn't match the frontmatter delimiter. - The local-overrides-plugin merge now keys on the frontmatter
name, asHOOKS.mdalways specified, rather than on the filename. - A discovery failure can no longer be mistaken for an empty hook. The empty-hook fast path is now defined as exit 0 with empty stdout; every other non-zero exit is an error reported loudly.
HOOKS.md's silent fallback to "local agents only" is also gone — quietly dropping the plugin's own bundled agents was itself a failure mode.
Added
- A command you can run yourself.
$(claude plugin path hcf)/hooks/discover-hooks.shprints what is enrolled at every hook;--hook=<name>for one,--jsonfor tooling. This is the fastest answer to "why didn't my agent fire?" — a question that previously had no answer at all, since the improvised script no longer existed by the time you asked. - Drift detection.
--fingerprintcaptures the resolved enrollment across all 8 hooks;plan-createstores it with the plan andplan-orchestratere-checks it on every hook call. If agent files change midway through a run, HCF halts and names what changed rather than silently finishing against a different pipeline than the plan was reviewed against. Agent body content is deliberately not covered — editing an agent's prose is not drift. - Test suite (
./tests/run-tests.sh) — 97 tests, no dependencies beyond bash/awk/sed/sort/grep, runs on bash 3.2 (stock macOS).
Changed
- An invalid
phaseormodenow aborts (exit 3) instead of being warned past. Previously an unknownphasewas ignored with a warning, which meant the agent ran nowhere — the same silent non-execution as the bug above, one level down. Validation is global, so the error surfaces at the first hook of a run rather than hours later at commit time. This can affect existing projects: an agent file with a typo'dphaseruns today (minus that agent) and will now halt planning until it is fixed. The error names the file, the bad value, and both remedies — correct the value, or remove thephasekey entirely to unenroll the agent. Onlyplan-createandplan-orchestratecall the script;/project-updateand every other skill stay runnable. HOOKS.md's Discovery Routine now documents what the script does rather than instructing the reader to enumerate agent files by hand.