Files
claude-code/plugins/plugin-dev/skills/hook-development/scripts
Claude 411381bf3e fix: Add missing matcher fields to hooks.json files
Stop hooks (and other hook types) were not firing because they were
missing the required "matcher" field. According to the hook development
documentation, all hooks must have a matcher field - "*" for wildcard
matching.

Changes:
- Add matcher: "*" to all hooks in hookify, ralph-wiggum,
  explanatory-output-style, and learning-output-style plugins
- Update validate-hook-schema.sh to properly handle plugin format
  (with 'hooks' wrapper) vs settings format (events at root)
- Add validate-all-hooks.sh script to validate all hooks.json files

Fixes: https://anthropic.slack.com/archives/C08EHE6JF3L/p1765822035850959
2025-12-15 18:14:58 +00:00
..

Hook Development Utility Scripts

These scripts help validate, test, and lint hook implementations before deployment.

validate-hook-schema.sh

Validates hooks.json configuration files for correct structure and common issues.

Usage:

./validate-hook-schema.sh path/to/hooks.json

Checks:

  • Valid JSON syntax
  • Required fields present
  • Valid hook event names
  • Proper hook types (command/prompt)
  • Timeout values in valid ranges
  • Hardcoded path detection
  • Prompt hook event compatibility

Example:

cd my-plugin
./validate-hook-schema.sh hooks/hooks.json

test-hook.sh

Tests individual hook scripts with sample input before deploying to Claude Code.

Usage:

./test-hook.sh [options] <hook-script> <test-input.json>

Options:

  • -v, --verbose - Show detailed execution information
  • -t, --timeout N - Set timeout in seconds (default: 60)
  • --create-sample <event-type> - Generate sample test input

Example:

# Create sample test input
./test-hook.sh --create-sample PreToolUse > test-input.json

# Test a hook script
./test-hook.sh my-hook.sh test-input.json

# Test with verbose output and custom timeout
./test-hook.sh -v -t 30 my-hook.sh test-input.json

Features:

  • Sets up proper environment variables (CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT)
  • Measures execution time
  • Validates output JSON
  • Shows exit codes and their meanings
  • Captures environment file output

hook-linter.sh

Checks hook scripts for common issues and best practices violations.

Usage:

./hook-linter.sh <hook-script.sh> [hook-script2.sh ...]

Checks:

  • Shebang presence
  • set -euo pipefail usage
  • Stdin input reading
  • Proper error handling
  • Variable quoting (injection prevention)
  • Exit code usage
  • Hardcoded paths
  • Long-running code detection
  • Error output to stderr
  • Input validation

Example:

# Lint single script
./hook-linter.sh ../examples/validate-write.sh

# Lint multiple scripts
./hook-linter.sh ../examples/*.sh

Typical Workflow

  1. Write your hook script

    vim my-plugin/scripts/my-hook.sh
    
  2. Lint the script

    ./hook-linter.sh my-plugin/scripts/my-hook.sh
    
  3. Create test input

    ./test-hook.sh --create-sample PreToolUse > test-input.json
    # Edit test-input.json as needed
    
  4. Test the hook

    ./test-hook.sh -v my-plugin/scripts/my-hook.sh test-input.json
    
  5. Add to hooks.json

    # Edit my-plugin/hooks/hooks.json
    
  6. Validate configuration

    ./validate-hook-schema.sh my-plugin/hooks/hooks.json
    
  7. Test in Claude Code

    claude --debug
    

Tips

  • Always test hooks before deploying to avoid breaking user workflows
  • Use verbose mode (-v) to debug hook behavior
  • Check the linter output for security and best practice issues
  • Validate hooks.json after any changes
  • Create different test inputs for various scenarios (safe operations, dangerous operations, edge cases)

Common Issues

Hook doesn't execute

Check:

  • Script has shebang (#!/bin/bash)
  • Script is executable (chmod +x)
  • Path in hooks.json is correct (use ${CLAUDE_PLUGIN_ROOT})

Hook times out

  • Reduce timeout in hooks.json
  • Optimize hook script performance
  • Remove long-running operations

Hook fails silently

  • Check exit codes (should be 0 or 2)
  • Ensure errors go to stderr (>&2)
  • Validate JSON output structure

Injection vulnerabilities

  • Always quote variables: "$variable"
  • Use set -euo pipefail
  • Validate all input fields
  • Run the linter to catch issues