Skip to content

fix: align hooks declaration with current Claude Code schema#4

Open
n-dryer wants to merge 1 commit into
Ahacad:mainfrom
n-dryer:fix/cc-hooks-schema
Open

fix: align hooks declaration with current Claude Code schema#4
n-dryer wants to merge 1 commit into
Ahacad:mainfrom
n-dryer:fix/cc-hooks-schema

Conversation

@n-dryer
Copy link
Copy Markdown

@n-dryer n-dryer commented May 2, 2026

Summary

The plugin currently fails to load on recent Claude Code (Status: ✘ failed to load). Two small schema fixes:

  • hooks/hooks.json — wrap the existing event map under a top-level "hooks": { ... } record. CC's hooks validator now requires this top-level key; without it, load fails with:

    hooks: Invalid input: expected record, received undefined

  • .claude-plugin/plugin.json — drop the \"hooks\": \"./hooks/hooks.json\" line. CC now auto-loads hooks/hooks.json by convention, so declaring it explicitly causes:

    Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file ... The standard hooks/hooks.json is loaded automatically, so manifest.hooks should only reference additional hook files.

Behavior is unchanged — the same SessionStart hook still fires ensure-setup.sh.

Repro before the fix

$ claude plugin validate <plugin-dir>
✘ Found 1 error:
  ❯ hooks: Invalid input: expected record, received undefined
$ claude plugin list | grep -A 4 gstack
  ❯ gstack@...
    Status: ✘ failed to load
    Error: Hook load failed: [{"expected":"record","code":"invalid_type","path":["hooks"],"message":"Invalid input: expected record, received undefined"}]

After

$ claude plugin validate <plugin-dir>
✔ Validation passed

$ claude plugin list | grep -A 3 gstack
  ❯ gstack@...
    Status: ✔ enabled

Tested via a wrapper marketplace pointing at this branch, on Claude Code installed from the Mac desktop app. SessionStart hook still runs ensure-setup.sh end-to-end (Playwright Chromium download + browse binary build + compat symlink).

Test plan

  • claude plugin validate <plugin-dir> → passes
  • Install via marketplace → Status: ✔ enabled in claude plugin list
  • Open a fresh CC session → SessionStart hook runs ensure-setup.sh, vendor/gstack/browse/dist/browse ends up built
  • Skills (browse, plan-ceo-review, plan-eng-review, qa, retro, review, setup-browser-cookies, ship) appear in the session's available-skills list

🤖 Generated with Claude Code

Two changes that together let the plugin load on current Claude Code
(it currently reports `Status: ✘ failed to load`):

1. `hooks/hooks.json` — wrap the existing event map under a top-level
   `"hooks": { ... }` record. Current CC validates the file with a
   schema that expects a top-level `hooks` field, otherwise it errors
   with `hooks: Invalid input: expected record, received undefined`.

2. `.claude-plugin/plugin.json` — drop the `"hooks": "./hooks/hooks.json"`
   line. Claude Code now auto-loads `hooks/hooks.json` by convention,
   so declaring it explicitly causes a duplicate-load error:
   `Duplicate hooks file detected: ./hooks/hooks.json resolves to
   already-loaded file ... The standard hooks/hooks.json is loaded
   automatically, so manifest.hooks should only reference additional
   hook files.`

Verified with `claude plugin validate` (passes) and `claude plugin list`
(`Status: ✔ enabled`) on Claude Code installed via the Mac desktop app.
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