Skip to content

hooks.json file fix (needed on my system anyway) #12

@darval

Description

@darval

hooks.json uses flat structure instead of required nested hooks array

Affected repos: zetetic-team-subagents (v2.0.0), Cortex (v3.9.0)
Files: hooks/hooks.json (subagents), .claude/hooks/hooks.json (Cortex)
Severity: Plugin fails to load — all hooks are broken

Problem

Claude Code's hook schema requires each hook entry to wrap type/command inside a nested hooks array. Both repos use a flat structure that puts type and command as siblings of matcher/when, which causes validation to reject every single hook entry:

Failed to load hooks from hooks.json:
  expected: "array", code: "invalid_type",
  path: ["hooks", "PreToolUse", 0, "hooks"],
  message: "Invalid input: expected array, received undefined"

This repeats for all 14 hook entries across PreToolUse (5), PostToolUse (4), PostToolUseFailure (1), SessionStart (2), Stop (1), and Notification (1).

Diff

The fix is mechanical — wrap each entry's type/command in a hooks: [...] array. The matcher and when fields stay at the outer level.

 {
   "hooks": {
     "PreToolUse": [
       {
         "matcher": "Bash",
         "when": "command contains 'git commit'",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-commit-zetetic.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-commit-zetetic.sh"
+          }
+        ]
       },
       {
         "matcher": "Bash",
         "when": "command contains 'git push'",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-push-review.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-push-review.sh"
+          }
+        ]
       },
       {
         "matcher": "Bash",
         "when": "command contains 'git push'",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-push-provenance.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-push-provenance.sh"
+          }
+        ]
       },
       {
         "matcher": "Edit|Write",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-edit-layer-check.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-edit-layer-check.sh"
+          }
+        ]
       },
       {
         "matcher": "Edit|Write",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-claim-gate.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-claim-gate.sh"
+          }
+        ]
       }
     ],
     "PostToolUse": [
       {
         "matcher": "Bash",
         "when": "command contains 'git commit'",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-commit-difficulty.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-commit-difficulty.sh"
+          }
+        ]
       },
       {
         "matcher": "Bash",
         "when": "command contains 'git commit'",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-commit-lab-notebook.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-commit-lab-notebook.sh"
+          }
+        ]
       },
       {
         "matcher": "Edit|Write",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-edit-balance.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-edit-balance.sh"
+          }
+        ]
       },
       {
         "matcher": "WebFetch|WebSearch",
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-research-provenance.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-research-provenance.sh"
+          }
+        ]
       }
     ],
     "PostToolUseFailure": [
       {
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-error-routing.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-error-routing.sh"
+          }
+        ]
       }
     ],
     "SessionStart": [
       {
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
+          }
+        ]
       },
       {
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-research.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-research.sh"
+          }
+        ]
       }
     ],
     "Stop": [
       {
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh"
+          }
+        ]
       }
     ],
     "Notification": [
       {
-        "type": "command",
-        "command": "${CLAUDE_PLUGIN_ROOT}/hooks/notification-handler.sh"
+        "hooks": [
+          {
+            "type": "command",
+            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/notification-handler.sh"
+          }
+        ]
       }
     ]
   }
 }

Reference

Working example from token-optimizer (v5.1.0) that uses the correct nested schema:

{
  "matcher": "Read",
  "hooks": [
    {
      "type": "command",
      "command": "python3 '${CLAUDE_PLUGIN_ROOT}/skills/token-optimizer/scripts/read_cache.py' --quiet"
    }
  ]
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions