The hey Claude Code plugin ships a SessionStart hook that never runs, because hooks.json sits one directory too deep.
What I see
In the installed plugin cache:
37signals/hey/1.4.1/
.claude-plugin/
hooks/hooks.json <- the declaration
hooks/session-start.sh
plugin.json
skills/
skills/ <- also present at the root
(no hooks/ at the root)
The sibling basecamp plugin, whose hooks do run, is laid out the other way:
37signals/basecamp/0.10.0/
.claude-plugin/
plugin.json <- only the manifest
hooks/hooks.json <- at the root
skills/
Evidence it never fires
The script itself is fine. Run by hand it works:
$ bash .claude-plugin/hooks/session-start.sh
<hook-output>
HEY plugin active.
</hook-output>
But across every Claude Code transcript on this machine since the plugin was installed on 2026-09-08, HEY plugin active appears exactly once, and that once is the manual run above. Basecamp's equivalent string appears in 18 sessions over the same period.
A probe session started with claude -p --include-hook-events --output-format stream-json records one hook_started for SessionStart, and its output is Basecamp's, not HEY's. Both plugins were enabled at the time.
Suggested fix
Move hooks/ to the repository root, next to skills/, matching basecamp-cli. ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh inside hooks.json then resolves as written.
Low impact, since the hook only prints a status line, but as it stands the plugin advertises a hook it does not deliver.
🤖 Generated with Claude Code
The
heyClaude Code plugin ships aSessionStarthook that never runs, becausehooks.jsonsits one directory too deep.What I see
In the installed plugin cache:
The sibling
basecampplugin, whose hooks do run, is laid out the other way:Evidence it never fires
The script itself is fine. Run by hand it works:
But across every Claude Code transcript on this machine since the plugin was installed on 2026-09-08,
HEY plugin activeappears exactly once, and that once is the manual run above. Basecamp's equivalent string appears in 18 sessions over the same period.A probe session started with
claude -p --include-hook-events --output-format stream-jsonrecords onehook_startedforSessionStart, and its output is Basecamp's, not HEY's. Both plugins were enabled at the time.Suggested fix
Move
hooks/to the repository root, next toskills/, matchingbasecamp-cli.${CLAUDE_PLUGIN_ROOT}/hooks/session-start.shinsidehooks.jsonthen resolves as written.Low impact, since the hook only prints a status line, but as it stands the plugin advertises a hook it does not deliver.
🤖 Generated with Claude Code