output_skills/ai/claude-code/creating-hooks/SKILL.md
Creates Claude Code hooks.
npx skillsauth add lexler/skill-factory creating-hooksInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
STARTER_CHARACTER = 🪝
First, update the reference docs to get the latest from Anthropic:
python ~/.claude/skills/creating-hooks/scripts/update-docs.py
Shell commands that execute at lifecycle points in Claude Code. Unlike prompts, hooks are deterministic—they always run when triggered.
Hooks live in settings files:
~/.claude/settings.json - User settings (all projects).claude/settings.json - Project settings (shared via git).claude/settings.local.json - Local project settings (not committed){
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
Matcher: Pattern to match tool names (case-sensitive)
WriteEdit|Write* or omitEnvironment variables:
$CLAUDE_PROJECT_DIR - Absolute path to project root$CLAUDE_ENV_FILE - File path for persisting env vars (SessionStart only)Tool events (matcher applies):
PreToolUse - Before tool executesPostToolUse - After tool completesPermissionRequest - Permission dialog shownSession events:
SessionStart - Session begins/resumes (matcher: startup/resume/clear/compact)SessionEnd - Session endsPreCompact - Before compaction (matcher: manual/auto)Other events:
UserPromptSubmit - User submits promptStop - Agent finishesSubagentStop - Subagent finishesNotification - Alerts sent (matcher: notification type)UserPromptSubmit/SessionStart, stdout added to context.For advanced control, return JSON to stdout with exit code 0:
{
"continue": false,
"stopReason": "Message shown when stopping"
}
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Auto-approved",
"updatedInput": { "field": "modified value" }
}
}
Decisions: "allow" (bypass permission), "deny" (block), "ask" (prompt user)
{
"decision": "block",
"reason": "Explanation fed to Claude"
}
{
"decision": "block",
"reason": "Must fix X before stopping"
}
Hooks receive JSON via stdin:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/current/dir",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": { "file_path": "/path", "content": "..." }
}
Auto-format after edit:
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -I{} sh -c 'echo {} | grep -q \"\\.ts$\" && npx prettier --write {}'"
}]
}]
}
}
Block dangerous commands:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/validate-bash.py"
}]
}]
}
}
Inject context on prompt:
{
"hooks": {
"UserPromptSubmit": [{
"hooks": [{
"type": "command",
"command": "echo '[REMINDER: Follow TDD]'"
}]
}]
}
}
Desktop notification:
{
"hooks": {
"Notification": [{
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"Claude needs input\" with title \"Claude Code\"'"
}]
}]
}
}
For complex logic, use external scripts. UV single-file format works well:
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = []
# requires-python = ">=3.11"
# ///
import json
import sys
data = json.load(sys.stdin)
tool_input = data.get("tool_input", {})
# Validation logic here
if should_block:
print("Error message", file=sys.stderr)
sys.exit(2)
sys.exit(0)
development
Test-driven development (TDD) process used when writing code. Use whenever you are adding any new code, unless the user explicitly asks to skip TDD or the code is exploratory/spike.
development
Writes tests without mocks using Nullables. Use when writing tests, especially testing code with external I/O (HTTP, files, databases, clocks, random numbers), designing infrastructure wrappers or replacing mocking libraries.
testing
Scannable BDD tests written in domain language. Use when doing BDD.
development
Writes approval tests (snapshot/golden master testing) for Python, JavaScript/TypeScript, or Java. Use when verifying complex output, characterization testing legacy code, testing combinations, or working with .approved/.received files.