Back to Skills

hooks-development

verified

Claude Code hooks development guide covering all 10 hook events lifecycle, PostToolUse visibility patterns, PreToolUse guards, Stop hook schema, and debugging. Use when creating hooks, troubleshooting hook output, understanding hook lifecycle, or when user mentions decision block, hook JSON output, stop hook, or Claude Code hooks.

View on GitHub

Marketplace

cc-skills

terrylica/cc-skills

Plugin

itp-hooks

enforcement

Repository

terrylica/cc-skills
8stars

plugins/itp-hooks/skills/hooks-development/SKILL.md

Last Verified

January 25, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/terrylica/cc-skills/blob/main/plugins/itp-hooks/skills/hooks-development/SKILL.md -a claude-code --skill hooks-development

Installation paths:

Claude
.claude/skills/hooks-development/
Powered by add-skill CLI

Instructions

# 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 `decision: block` pattern
- 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 `decision: block` | Not visible       |
| JSON with `decision: block`    | Visible           |

**Exit code behavior**:

| Exit Code | stdout Behavior                         | Claude Visibility             |
| --------- | --------------------------------------- | ----------------------------- |
| **0**     | JSON parsed, shown in verbose mode only | Only if `"decision": "block"` |
| **2**     | Ignored, uses stderr instead            | stderr shown to Claude        |
| **Other** | stderr shown in verbose mode            | Not shown to Claude           |

---

## Minimal Working Pattern

```bash
/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**:

1. Use `jq -n` to generate valid JSON
2. Include `"decision": "block"` for visibility
3. Exit with code 0
4. The "blocking error" label is cosmetic - operation continues

---

## TodoWrite Templates

### Creating a PostToolUse Hook

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
3641 chars