Skip to content

Align the repo with the plugin and hook references - #5

Merged
jackyraimond merged 1 commit into
mainfrom
plugin-conformance
Aug 12, 2026
Merged

Align the repo with the plugin and hook references#5
jackyraimond merged 1 commit into
mainfrom
plugin-conformance

Conversation

@jackyraimond

Copy link
Copy Markdown
Collaborator

Three findings from reading the plugins reference and the hooks reference against what this repo actually does.

1. Our validator rejected valid hooks

validate.sh knew nine hook events. Claude Code ships around thirty. A contributor opening a PR for a hook on PostToolUseFailure, PermissionRequest, FileChanged, SubagentStart, TaskCompleted, PostCompact, Setup or CwdChanged would have been told by our own CI that the event does not exist.

The list is now complete as of today, but more importantly an unknown event is a warning, not a failure. This list will go stale again, and a validator that is one release behind should not block work it has no business blocking. A typo still surfaces — verified: FileChanged passes clean, PostToolUze warns and the build stays green.

2. There is an official validator we were not using

claude plugin validate ./hooks/<name> --strict

It checks the manifest against the real schema and catches what ours cannot: a misspelled field name (it even suggests the intended one), a value of the wrong type, a field left over from another tool's manifest. --strict turns warnings into errors, which is what you want before publishing.

Added as a plugin-validate job. It is deliberately not in the ruleset's required checks yet — it installs Claude Code from npm on every run, so let it prove itself over a few PRs first, then add it.

The marketplace manifest is validated without --strict: the official validator warns about a catalog with no plugins, which is the correct state for main until a hook merges. It also warned that the marketplace had no description, so that is fixed too.

3. Shell form was the wrong default

The template handed a string to sh -c:

{ "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/my-new-hook.py" }

Exec form spawns the script directly, no shell involved, and the docs recommend it whenever a path placeholder is in play:

{ "command": "python3", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/my-new-hook.py"] }

Quoting, spaces and $ in a path stop being the author's problem. validate.sh now understands both forms — shell form stays supported for hooks that genuinely need a pipe or &&.

Also

  • Manifest metadata the schema supports: $schema (editor autocomplete), keywords, license, homepage, repository.
  • A README section on the features we are not yet using: userConfig, defaultEnabled, async/asyncRewake, the if filter, ${CLAUDE_PLUGIN_DATA}.
  • CONTRIBUTING now states that anything deciding what a hook may do belongs in userConfig, not in a file inside the project. That rule exists because of a real hole, fixed separately in the project-checks PR.

Testing

./scripts/validate.sh and claude plugin validate --strict both pass. Command-form handling was tested four ways: exec form resolves the script, shell form still resolves it, exec form without ${CLAUDE_PLUGIN_ROOT} fails, and a hard-coded personal path in args fails.

🤖 Generated with Claude Code

Three changes, all from reading the official references properly.

The event list no longer blocks. validate.sh knew nine events; Claude
Code ships around thirty, so a hook on PostToolUseFailure, FileChanged,
PermissionRequest or SubagentStart would have been rejected by our own
CI as "unknown". The list is now complete as of today, and an event
missing from it is a warning rather than a failure — a validator that is
one release behind should not block work it has no business blocking. A
typo still surfaces, which was the only real point.

CI now also runs Claude Code's own validator. `claude plugin validate
--strict` checks each hook manifest against the real schema and catches
what ours cannot: misspelled field names, values of the wrong type,
leftovers from another tool's manifest. The marketplace manifest is
checked without --strict, because the official validator warns about a
catalog with no plugins and that is the correct state for main until a
hook merges.

The template moves to exec form: the interpreter in `command`, the
script in `args`. That spawns the script directly instead of handing a
string to sh -c, so quoting and spaces stop being a source of bugs. The
docs recommend it whenever a path placeholder is involved. validate.sh
now understands both forms, and shell form stays supported for hooks
that genuinely need a pipe.

Also adds the manifest metadata the schema supports ($schema for editor
autocomplete, keywords, license, homepage, repository), a description
for the marketplace itself, and a README section on userConfig,
defaultEnabled, async/asyncRewake, the `if` filter and
${CLAUDE_PLUGIN_DATA}.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jackyraimond
jackyraimond merged commit a374560 into main Aug 12, 2026
5 checks passed
@jackyraimond
jackyraimond deleted the plugin-conformance branch August 12, 2026 07:51
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