[DOCS] Mods: document that each event allows only one matcher-less on() registration per plugin

Status Open
Reported on v2.1.296
Maintainer reply None cached
Activity 0 comments · opened Oct 12, 2026

Documentation Type

Missing documentation (feature not documented)

Documentation Location

The plugin-authoring skill (SKILL.md, reference.md) and the On / Register doc comments in the mods type declarations (.claude-plugin/types/claude-code/index.d.ts).

Section/Topic

Registering hooks with on(event, matcher?, hook): how many registrations an event may have

Current Documentation

The docs describe on(event, matcher?, hook) and matchers, but do not say that an event may be registered without a matcher only once per plugin.

What's Wrong or Missing?

claude plugin validate (and the loader) refuses a hooks module that registers the same event twice without a matcher — for any event, not just session.start:

export const register: Register = on => {
  on('turn.complete', ($, e, next) => next(e))
  on('turn.complete', ($, e, next) => next(e))
}
✘ modules../register.ts: on("turn.complete") is registered twice without a matcher; the first is at ...register.ts:2; ...

Registrations with a matcher may repeat, even with an identical matcher:

on('turn.complete', { reason: 'answer' }, ($, e, next) => next(e))
on('turn.complete', { reason: 'answer' }, ($, e, next) => next(e)) // accepted

Because hooks.json takes a single modules path, a plugin made of several features wires them from one hooks module, and several features naturally observe the same lifecycle events (session.start, turn.complete, prompt.submit). Discovering this rule late forces a redesign: an event-ownership table and artificial matchers such as { isInteractive: true }, { reason: 'answer' }, { origin: { kind: 'composer' } }. Events whose input has no literal discriminant (e.g. session.measure) cannot be shared at all.

Suggested Improvement

  1. State the rule in reference.md / the skill's "A mod in one paragraph" and in the On doc comment, with the matcher workaround.
  2. Consider allowing repeated matcher-less registrations (chained in registration order, as matcher registrations already are), or provide a way to share an event that has no discriminant.

Impact

Medium - Makes feature difficult to understand

Additional Context

  • Claude Code 2.1.296 (type declarations written by 2.1.295), Windows 11.
  • Related: #100984 (another rule claude plugin validate enforces or misses without documentation).

View original on GitHub ↗