Skip to content
creating-claude-hooks logo

Creating Claude Code Hooks

creating-claude-hooks

Use when creating or publishing Claude Code hooks - covers executable format, event types, JSON I/O, exit codes, security requirements, and PRPM package structure

SKILL.md

Full skill instructions

Creating Claude Code Hooks

Use this skill when creating, improving, or publishing Claude Code hooks. Provides essential guidance on hook format, event handling, I/​O conventions, and package structure.

When to Use This Skill

Activate this skill when:

  • User asks to create a new Claude Code hook
  • User wants to publish a hook as a PRPM package
  • User needs to understand hook format or events
  • User is troubleshooting hook execution
  • User asks about hook vs skill vs command differences

Quick Reference

Hook File Format

AspectRequirement
Location.claude/​hooks/<event-name>
FormatExecutable file (shell, TypeScript, Python, etc.)
PermissionsMust be executable (chmod +x)
ShebangRequired (#!/​bin/​bash or #!/​usr/​bin/​env node)
InputJSON via stdin
OutputText via stdout (shown to user)
Exit Codes0 = success, 2 = block, other = error

Available Events

EventWhen It FiresCommon Use Cases
session-startNew session beginsEnvironment setup, logging, checks
user-prompt-submitBefore user input processesValidation, enhancement, filtering
tool-callBefore tool executionPermission checks, logging, modification
assistant-responseAfter assistant respondsFormatting, logging, cleanup

Hook Format Requirements

File Location

Project hooks:

.claude/​hooks/​session-start
.claude/​hooks/​user-prompt-submit

User-global hooks:

~/​.claude/​hooks/​session-start
~/​.claude/​hooks/​tool-call

Executable Requirements

Every hook MUST:

  1. Have a shebang line:
#!/​bin/​bash
# or
#!/​usr/​bin/​env node
# or
#!/​usr/​bin/​env python3
  1. Be executable:
chmod +x .claude/​hooks/​session-start
  1. Handle JSON input from stdin:
#!/​bin/​bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
  1. Exit with appropriate code:
exit 0  # Success
exit 2  # Block operation
exit 1  # Error (logs but continues)

Input/​Output Format

JSON Input Structure

Hooks receive JSON via stdin with event-specific data:

{
  "event": "tool-call",
  "timestamp": "2025-01-15T10:30:00Z",
  "session_id": "abc123",
  "current_dir": "/​path/​to/​project",
  "input": {
    "file_path": "/​path/​to/​file.ts",
    "command": "npm test",
    "old_string": "...",
    "new_string": "..."
  }
}

Stdout Output

  • Normal output shows in transcript
  • Empty output runs silently
  • Use stderr (>&2) for errors

Exit Codes

CodeMeaningBehavior
0SuccessContinue normally
2BlockStop operation, show error
1 or otherErrorLog error, continue

Schema Validation

Hooks should validate against the JSON schema:

Schema URL: https://github.com/pr-pm/prpm/blob/main/packages/converters/schemas/claude-hook.schema.json

Required frontmatter fields:

  • name - Hook identifier (lowercase, hyphens only)
  • description - What the hook does
  • event - Event type (optional, inferred from filename)
  • language - bash, typescript, javascript, python, binary (optional)
  • hookType: "hook" - For round-trip conversion

Common Mistakes

MistakeProblemSolution
Not quoting variablesBreaks on spacesAlways use "$VAR"
Missing shebangWon't executeAdd #!/​bin/​bash
Not executablePermission deniedRun chmod +x hook-file
Logging to stdoutClutters transcriptUse stderr: echo "log" >&2
Wrong exit codeDoesn't block when neededUse exit 2 to block
No input validationSecurity riskAlways validate JSON fields
Slow operationsBlocks ClaudeRun in background or use PostToolUse
Absolute paths missingCan't find scriptsUse $CLAUDE_PLUGIN_ROOT

Basic Hook Examples

Shell Script Hook

#!/​bin/​bash
# .claude/​hooks/​session-start

# Log session start
echo "Session started at $(date)" >> ~/​.claude/​session.log

# Check environment
if ! command -v node &> /​dev/​null; then
  echo "Warning: Node.js not installed" >&2
fi

# Output to user
echo "Development environment ready"
exit 0

TypeScript Hook

#!/​usr/​bin/​env node
// .claude/​hooks/​user-prompt-submit

import { readFileSync } from 'fs';

// Read JSON from stdin
const input = readFileSync(0, 'utf-8');
const data = JSON.parse(input);

// Validate prompt
if (data.prompt.includes('API_KEY')) {
  console.error('Warning: Prompt may contain secrets');
  process.exit(2); // Block
}

console.log('Prompt validated');
process.exit(0);

Best Practices

1. Keep Hooks Fast

Target < 100ms for PreToolUse hooks:

  • Cache results where possible
  • Run heavy operations in background
  • Use specific matchers, not wildcards

2. Handle Errors Gracefully

# Check dependencies exist
if ! command -v jq &> /​dev/​null; then
  echo "jq not installed, skipping" >&2
  exit 0
fi

# Validate input
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
if [[ -z "$FILE" ]]; then
  echo "No file path provided" >&2
  exit 1
fi

3. Use Shebangs

Always start with shebang:

#!/​bin/​bash
#!/​usr/​bin/​env node
#!/​usr/​bin/​env python3

4. Secure Sensitive Files

BLOCKED=(".env" ".env.*" "*.pem" "*.key")
for pattern in "${BLOCKED[@]}"; do
  case "$FILE" in
    $pattern)
      echo "Blocked: $FILE is sensitive" >&2
      exit 2
      ;;
  esac
done

5. Quote All Variables

# WRONG - breaks on spaces
prettier --write $FILE

# RIGHT - handles spaces
prettier --write "$FILE"

6. Log for Debugging

LOG_FILE=~/​.claude-hooks/​debug.log

# Log to file
echo "[$(date)] Processing $FILE" >> "$LOG_FILE"

# Log to stderr (shows in transcript)
echo "Hook running..." >&2

Publishing as PRPM Package

Package Structure

my-hook/
├── prpm.json          # Package manifest
├── HOOK.md            # Hook documentation
└── hook-script.sh     # Hook executable

prpm.json

{
  "name": "@username/​hook-name",
  "version": "1.0.0",
  "description": "Brief description shown in search",
  "author": "Your Name",
  "format": "claude",
  "subtype": "hook",
  "tags": ["automation", "security", "formatting"],
  "main": "HOOK.md"
}

HOOK.md Format

---
name: session-logger
description: Logs session start/​end times for tracking
event: SessionStart
language: bash
hookType: hook
---

# Session Logger Hook

Logs Claude Code session activity for tracking and debugging.

## Installation

This hook will be installed to `.claude/​hooks/​session-start`.

## Behavior

- Logs session start time to `~/​.claude/​session.log`
- Displays environment status
- Runs silent dependency checks

## Requirements

- bash 4.0+
- write access to `~/​.claude/`

## Source Code

\`\`\`bash
#!/​bin/​bash
echo "Session started at $(date)" >> ~/​.claude/​session.log
echo "Environment ready"
exit 0
\`\`\`

Publishing Process

# Test locally first
prpm test

# Publish to registry
prpm publish

# Version bumps
prpm publish patch  # 1.0.0 -> 1.0.1
prpm publish minor  # 1.0.0 -> 1.1.0
prpm publish major  # 1.0.0 -> 2.0.0

Security Requirements

Input Validation

# Parse JSON safely
INPUT=$(cat)
if ! FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty' 2>&1); then
  echo "JSON parse failed" >&2
  exit 1
fi

# Validate field exists
[[ -n "$FILE" ]] || exit 1

Path Sanitization

# Prevent directory traversal
if [[ "$FILE" == *".."* ]]; then
  echo "Path traversal detected" >&2
  exit 2
fi

# Keep in project directory
if [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then
  echo "File outside project" >&2
  exit 2
fi

User Confirmation

Claude Code automatically:

  • Requires confirmation before installing hooks
  • Shows hook source code to user
  • Warns about hook execution
  • Displays hook output in transcript

Hooks vs Skills vs Commands

FeatureHooksSkillsCommands
FormatExecutable codeMarkdownMarkdown
TriggerAutomatic (events)Automatic (context)Manual (/​command)
LanguageAny executableN/​AN/​A
Use CaseAutomation, validationReference, patternsQuick tasks
SecurityRequires confirmationNo special permissionsInherits from session

Examples:

  • Hook: Auto-format files on save
  • Skill: Reference guide for testing patterns
  • Command: /​review-pr quick code review

Related Resources

  • claude-hook-writer skill - Detailed hook development guidance
  • typescript-hook-writer skill - TypeScript-specific hook development
  • Claude Code Docs
  • Schema

Checklist for New Hooks

Before publishing:

  • Shebang line included
  • File is executable (chmod +x)
  • Validates all stdin input
  • Quotes all variables
  • Handles missing dependencies gracefully
  • Uses appropriate exit codes
  • Logs errors to stderr or file
  • Tests with edge cases (spaces, Unicode, missing fields)
  • Documents dependencies in HOOK.md
  • Includes installation instructions
  • Source code included in documentation
  • Clear description and tags in prpm.json
  • Version number is semantic

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View