Skip to content

fix(hooks): conform hooks.json to Claude Code plugin hook schema (fixes plugin failing to load)#1

Open
TroyMiner wants to merge 1 commit into
DojoCodingLabs:mainfrom
TroyMiner:fix/hooks-json-schema
Open

fix(hooks): conform hooks.json to Claude Code plugin hook schema (fixes plugin failing to load)#1
TroyMiner wants to merge 1 commit into
DojoCodingLabs:mainfrom
TroyMiner:fix/hooks-json-schema

Conversation

@TroyMiner

Copy link
Copy Markdown

Summary

hooks/hooks.json is not valid against the Claude Code plugin hook schema, which causes the entire plugin to fail to load (Status: ✘ failed to load, Hooks: 0). This PR makes the file spec-compliant.

The validation error Claude Code reports:

Hook load failed: [
  { "expected": "array", "code": "invalid_type",
    "path": ["hooks", "PreToolUse", 0, "hooks"] }
]

Root cause

Each matcher entry was written in a flat shape, with type/command/timeout as siblings of matcher. The schema requires each matcher to contain a nested hooks: [] array of actions (see the official superpowers/codex plugins). Three defects, all stemming from not following the hook spec:

# Defect Effect
A Missing per-matcher hooks: [] wrapper Plugin fails to load (the error above)
B timeout in ms (5000/3000) Claude Code timeouts are in seconds β€” 5000 would block for ~83 min
C Relative sh scripts/... paths Hooks run from the user's project dir, so the scripts aren't found

Fix

  • Wrap each matcher's action in a hooks: [] array.
  • Convert timeouts to seconds (5/3).
  • Reference scripts via ${CLAUDE_PLUGIN_ROOT}/scripts/..., matching the official plugins.

Behaviour (which servers/keys are checked, matchers, notes emitted) is unchanged.

Test plan

  • claude plugin validate . passes
  • hooks.json parses as valid JSON
  • After applying, claude plugin list shows remotion-superpowers as βœ” enabled and claude plugin details reports Hooks (2) PreToolUse, PostToolUse (was Hooks (0) + failed to load)

πŸ€– Generated with Claude Code

PreToolUse/PostToolUse entries were flattened (type/command/timeout as
siblings of matcher), missing the required per-matcher `hooks: []` array.
This fails schema validation with
"hooks.PreToolUse[0].hooks: expected array" and makes the entire plugin
fail to load (Status: failed to load; Hooks: 0).

Wrapping each matcher's action in a `hooks` array fixes the load failure.
Also corrects two latent runtime defects in the same file:

- timeouts were in milliseconds (5000/3000); Claude Code hook timeouts
  are in seconds. Corrected to 5/3 (5000s would block for ~83 min).
- command paths were relative (`sh scripts/...`); hooks execute from the
  user's project directory, so the scripts are not found. Use
  `${CLAUDE_PLUGIN_ROOT}/scripts/...` as the official plugins do.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

βœ… Approved

Approved β€” 0 blockers, 4 P3. Confidence: 4/5.

πŸ”΅ P3 β€” Minor / nit

  • hooks/hooks.json:9 β€” πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax (such as pipefail or arrays) is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" remotion-media KIE_API_KEY",
  • hooks/hooks.json:19 β€” πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" replicate REPLICATE_API_TOKEN",
  • hooks/hooks.json:31 β€” πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" pexels-attribution",
  • hooks/hooks.json:41 β€” πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" captions-tip",

Total findings: 4 business context (4 total)

Comment thread hooks/hooks.json
"hooks": [
{
"type": "command",
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" remotion-media KIE_API_KEY",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax (such as pipefail or arrays) is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.

Suggested change
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" remotion-media KIE_API_KEY",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" remotion-media KIE_API_KEY",

Comment thread hooks/hooks.json
"hooks": [
{
"type": "command",
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" replicate REPLICATE_API_TOKEN",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.

Suggested change
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" replicate REPLICATE_API_TOKEN",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/check-mcp-server.sh\" replicate REPLICATE_API_TOKEN",

Comment thread hooks/hooks.json
"hooks": [
{
"type": "command",
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" pexels-attribution",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.

Suggested change
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" pexels-attribution",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" pexels-attribution",

Comment thread hooks/hooks.json
"hooks": [
{
"type": "command",
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" captions-tip",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ”΅ P3 (minor) β€” Running the hook with POSIX 'sh' ignores the script's bash shebang ('#!/bin/bash'). If bash-specific syntax is introduced in the script, execution under 'sh' can fail. Running it with 'bash' avoids potential shell compatibility issues.

Suggested change
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" captions-tip",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-note.sh\" captions-tip",

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