Claude-skill-registry hooks-development
Claude Code hooks development guide. TRIGGERS - create hook, PostToolUse, PreToolUse, Stop hook, hook lifecycle, decision block.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/hooks-development" ~/.claude/skills/majiayu000-claude-skill-registry-hooks-development && rm -rf "$T"
manifest:
skills/data/hooks-development/SKILL.mdsource content
Hooks Development
Guide for developing Claude Code hooks with proper output visibility patterns.
When to Use This Skill
- Creating a new PostToolUse or PreToolUse hook
- Hook output is not visible to Claude (most common issue)
- User asks about
patterndecision: block - Debugging why hook messages don't appear
- User mentions "Claude Code hooks" or "hook visibility"
Quick Reference: Visibility Patterns
Critical insight: PostToolUse hook stdout is only visible to Claude when JSON contains
"decision": "block".
| Output Format | Claude Visibility |
|---|---|
| Plain text | Not visible |
JSON without | Not visible |
JSON with | Visible |
Exit code behavior:
| Exit Code | stdout Behavior | Claude Visibility |
|---|---|---|
| 0 | JSON parsed, shown in verbose mode only | Only if |
| 2 | Ignored, uses stderr instead | stderr shown to Claude |
| Other | stderr shown in verbose mode | Not shown to Claude |
Minimal Working Pattern
/usr/bin/env bash << 'SKILL_SCRIPT_EOF' #!/usr/bin/env bash set -euo pipefail # Read hook payload from stdin PAYLOAD=$(cat) FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty') [[ -z "$FILE_PATH" ]] && exit 0 # Your condition here if [[ condition_met ]]; then jq -n \ --arg reason "[HOOK] Your message to Claude" \ '{decision: "block", reason: $reason}' fi exit 0 SKILL_SCRIPT_EOF
Key points:
- Use
to generate valid JSONjq -n - Include
for visibility"decision": "block" - Exit with code 0
- The "blocking error" label is cosmetic - operation continues
TodoWrite Templates
Creating a PostToolUse Hook
1. [pending] Create hook script with shebang and set -euo pipefail 2. [pending] Parse PAYLOAD from stdin with jq 3. [pending] Add condition check for when to trigger 4. [pending] Output JSON with decision:block pattern 5. [pending] Register hook in hooks.json with matcher 6. [pending] Test by editing a matching file 7. [pending] Verify Claude sees the message in system-reminder
Debugging Invisible Hook Output
1. [pending] Verify hook executes (add debug log to /tmp) 2. [pending] Check JSON format is valid (pipe to jq .) 3. [pending] Confirm decision:block is present in output 4. [pending] Verify exit code is 0 5. [pending] Check hooks.json matcher pattern 6. [pending] Restart Claude Code session
Reference Documentation
- Lifecycle Reference - All 10 hook events, diagrams, use cases, configuration pitfalls
- Visibility Patterns - Full exit code and JSON schema details
- Hook Templates - Copy-paste templates for common patterns
- Debugging Guide - Troubleshooting invisible output
Post-Change Checklist (Self-Evolution)
When this skill is updated:
- Update evolution-log.md with discovery
- Verify code examples still work
- Check if ADR needs updating: PostToolUse Hook Visibility ADR
Related Resources
- ADR: PostToolUse Hook Visibility
- GitHub Issue #3983 - Original bug report
- Claude Code Hooks Reference - Official documentation