Build event-driven hooks in Claude Code for validation, setup, and automation. Use when you need to validate inputs, check environment state, or automate tasks at specific lifecycle events.
Creates event-driven hooks that validate inputs, check environments, and automate tasks at lifecycle events.
/plugin marketplace add jack-michaud/faire/plugin install jack-michaud-jack-software-jack-software@jack-michaud/faireThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Hooks are event-driven scripts that execute at specific points in Claude Code's lifecycle. They receive JSON input with session data and event-specific information, enabling validation, environment checks, and automated workflows.
Runs before tool execution. Use for:
Runs after tool completion. Use for:
Runs before processing user input. Use for:
Runs at session initialization. Use for:
Runs at session termination. Use for:
{
"session_id": "unique-session-identifier",
"transcript_path": "/path/to/conversation.json",
"cwd": "/current/working/directory",
"hook_event_name": "PreToolUse|PostToolUse|UserPromptSubmit|SessionStart|SessionEnd"
}
PreToolUse:
{
"tool_name": "Bash",
"tool_input": {
"command": "pytest tests/",
"description": "Run test suite"
}
}
PostToolUse:
{
"tool_name": "Edit",
"tool_input": {
"file_path": "/path/to/file.py",
"old_string": "...",
"new_string": "..."
},
"tool_response": {
"success": true,
"message": "File edited successfully"
}
}
UserPromptSubmit:
{
"prompt": "User's input text here"
}
SessionStart:
{
"source": "startup|resume"
}
SessionEnd:
{
"reason": "user_exit|error|timeout"
}
Always use $CLAUDE_PROJECT_DIR to reference hook scripts. Claude Code sets this environment variable to your project root, ensuring hooks work regardless of the current working directory.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
Why this matters:
./scripts/hook.sh become fragile$CLAUDE_PROJECT_DIR always points to your project rootNote: The environment variable is only available when Claude Code spawns the hook command.
Add hooks to .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/scripts/pre-tool-hook.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/scripts/validate-edits.sh"
}
]
}
]
}
}
* - Match all toolsEdit - Match specific toolEdit|Write - Match multiple toolsBash(git:*) - Match tool with patternUse case: Warn if working directory is dirty before file operations
#!/bin/bash
# scripts/pre-tool-git-check.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Edit" || "$TOOL_NAME" == "Write" ]]; then
if ! git diff-index --quiet HEAD --; then
echo "⚠️ Warning: Uncommitted changes in working directory"
echo "Consider committing before editing files"
fi
fi
exit 0 # Don't block, just warn
Configuration:
{
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{"type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/scripts/pre-tool-git-check.sh"}]
}]
}
Use case: Auto-format Python files after editing
#!/bin/bash
# scripts/post-edit-format.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
if [[ "$TOOL_NAME" == "Edit" && "$FILE_PATH" == *.py ]]; then
black "$FILE_PATH" --quiet
echo "✅ Formatted $FILE_PATH with black"
fi
exit 0
Use case: Verify dependencies exist before starting
#!/bin/bash
# scripts/session-start-check.sh
MISSING=()
command -v python >/dev/null || MISSING+=("python")
command -v git >/dev/null || MISSING+=("git")
command -v jq >/dev/null || MISSING+=("jq")
if [ ${#MISSING[@]} -gt 0 ]; then
echo "❌ Missing dependencies: ${MISSING[*]}"
exit 1 # Block session
fi
echo "✅ All dependencies available"
exit 0
$CLAUDE_PROJECT_DIR for hook script paths"$CLAUDE_PROJECT_DIR"/scripts/hook.sh./scripts/hook.sh (breaks if CWD changes)/home/user/project/... (not portable)jq for robust JSON parsing# Check for uncommitted changes
git diff-index --quiet HEAD --
# Get current branch
git branch --show-current
# Check if file is tracked
git ls-files --error-unmatch "$FILE_PATH"
# Python
pylint "$FILE_PATH" --score=no --msg-template='{msg_id}: {msg}'
# JavaScript
eslint "$FILE_PATH" --format=compact
# Go
golint "$FILE_PATH"
# Run tests related to changed file
pytest "tests/test_${FILENAME}" --quiet
# Fast syntax check only
python -m py_compile "$FILE_PATH"
❌ Don't: Use relative or absolute paths for hook commands
$CLAUDE_PROJECT_DIR for portable, reliable paths❌ Don't: Use hooks for long-running tasks
❌ Don't: Block on non-critical checks
❌ Don't: Parse JSON with string manipulation
jq for reliable parsing❌ Don't: Match all tools without filtering
❌ Don't: Ignore hook failures silently
man jq or https://jqlang.github.io/jq/This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.