To author, register, and test Rosetta hooks, add a SemanticKind, or debug a hook that won't fire.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
<hooks_authoring>
Only files that export defineHook(…) AND call runAsCli(hook, module) belong directly in src/hooks/src/hooks/.
Every .ts at the top level of that directory becomes a standalone CJS bundle distributed to all 5 IDEs (claude, codex, copilot, cursor, windsurf).
Helper/data files without runAsCli belong in a named subdirectory: src/hooks/src/hooks/<feature>/.
src/hooks/src/hooks/<feature>/ (e.g. src/hooks/src/hooks/dangerous-actions/patterns.ts).src/hooks/src/runtime/.src/hooks/scripts/build-bundles.mjs:24 uses readdirSync(hooksDir).filter(f => f.endsWith('.ts')).
There is no { recursive: true }. Subdirectories are invisible to the bundler.
Adding a top-level .ts without runAsCli produces a dead bundle for all 5 IDEs.
When a hook needs a new tool category (e.g. mcp-call):
src/hooks/src/runtime/ide-registry.ts — add a row to TOOL_KINDS with all 5 IDE columns (null where the event doesn't exist). SemanticKind = keyof typeof TOOL_KINDS so TypeScript enforces coverage.src/hooks/src/runtime/ide-rows/<ide>.ts — if the kind requires special logic (e.g. prefix-match for mcp__.*), add a conditional branch at the top of lookupToolKind in the IDE-row file before the table loop. Table-driven lookup alone cannot handle open-ended tool name patterns.def.on.toolKinds.hooks.json.tmpl — widen to include new tool names/patterns.Order matters: run-hook.ts:98 gates on toolKinds before calling run(ctx). Matcher passes the event in; toolKinds must include the mapped kind or the call is dropped silently.
Every new hook must appear in every plugin's hooks.json. The canonical source is plugins/core-claude/hooks/hooks.json.tmpl (and equivalent templates in other plugins). Direct edits to generated hooks.json files are overwritten on the next npx rosettify-plugins run.
Paths by plugin:
plugins/core-claude/hooks/hooks.json.tmpl → hooks.jsonplugins/core-copilot/hooks/hooks.json.tmpl → hooks/hooks.jsonplugins/core-cursor/.cursor/hooks/hooks.json.tmpl → hooks.jsonplugins/core-codex/.codex/hooks/hooks.json.tmpl → hooks.jsonplugins/core-windsurf/ — bundles are distributed but hooks.json registration is not covered by the regression test (hooks-registered.test.ts); register manually if needed.PreToolUse is absent on Copilot ('copilot': null in ide-registry.ts). If a hook uses a platform-exclusive event, add its name to CLAUDE_CODE_ONLY_HOOKS Set in src/hooks/tests/regression/hooks-registered.test.ts. Before adding a second scoped hook, refactor the Set to Map<string, Set<IdeName>>.
Co-locate tests in src/hooks/tests/<hook-name>.test.ts. The regression test (src/hooks/tests/regression/hooks-registered.test.ts) automatically discovers all .ts entries at src/hooks/src/hooks/ top level and asserts each is referenced in every plugin's hooks.json. A new hook without registration immediately fails the regression guard.
After any source change under src/hooks/src/ or instructions/r{2,3}/core/:
venv/bin/python scripts/pre_commit.pyThis builds CJS bundles, runs full test suite, and runs npx rosettify-plugins to sync instructions/r{2,3}/core/ → all plugin directories.
isLibraryModule workaround. Fix: move to subdirectory.buildDenyMessage echoes evidence to transcript by default. Pass redact=true for DANGEROUS_CONTENT matches (AWS keys, PEM certs, SQL with row data).[rf]{2,} false positives — matches rm -rr and rm -ff. Require both flags with lookaheads: /\brm\s+-(?=[a-zA-Z]*[rR])(?=[a-zA-Z]*[fF])[a-zA-Z]+\b/.$-anchor vs trailing slash — path patterns like /\.kube\/config$ fail when tested against filePath with trailing slash. Always test against normalizedPath = filePath.replace(/\/+$/, '').lookupToolKind and def.on.toolKinds is inert.src/hooks/scripts/build-bundles.mjs
src/hooks/src/runtime/ide-registry.ts
src/hooks/src/runtime/ide-rows/claude-code.ts
src/hooks/src/runtime/run-hook.ts:98
plugins/core-claude/hooks/hooks.json.tmpl
src/hooks/tests/regression/hooks-registered.test.ts</hooks_authoring>
044d86c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.