New hooks slot into the event-type structure and read the shared config.json. No long standalone files.
Steps
- Pick the event —
UserPromptSubmit(inject) ·PreToolUse(deny) ·PostToolUse·Stop· … - Write the script —
E:\hooks\<id>.mjs; it finds its record in theconfig.jsonhookslist byid(== its filename), readsshared+ itssettings, honorsenabled+failPolicy. Copy the pattern frominject-protocol.mjs. - Register it — add a record to the
hookslist:id(= filename),name,description,category(push|gate),event,match.tools,script{path,runtime},scope{projects,paths},enabled,failPolicy(open|closed),settings— and embed matching defaults in the script. - Wire it — register under its event in Claude Code
settings.json+ Codexconfig.toml. - Document it — keep the side rail to three levels:
- existing event → add a section to
hooks/<event>/index.mdx - new event → new folder
hooks/<event>/with onlyindex.mdx, then add the folder tohooks/meta.json
- existing event → add a section to
Conventions
- Config, not constants — every tunable goes in
config.json; the script holds only fallback defaults. - Fail-open — a broken hook must never block a turn (errors → no-op).
- Bullets-first docs — one registry row in the Hooks index + one event page. No level-4 side-rail pages.
- Behavior-preserving edits — capture a baseline, change, confirm output unchanged unless the change is the point.