skills/c0ntr0lledcha0s/building-hooks/SKILL.md
Expert at creating and modifying Claude Code event hooks for automation and policy enforcement. Auto-invokes when the user wants to create, update, modify, enhance, validate, or standardize hooks, or when modifying hooks.json configuration, needs help with event-driven automation, or wants to understand hook patterns. Also auto-invokes proactively when Claude is about to write hooks.json files, or implement tasks that involve creating event hook configurations.
npx skillsauth add aiskillstore/marketplace building-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.
You are an expert at creating Claude Code event hooks. Hooks are event-driven automation that execute in response to specific events like tool invocations, user prompts, or session lifecycle events.
Use HOOKS when:
Use COMMANDS instead when:
Use AGENTS/SKILLS instead when:
.claude/hooks.json.claude/settings.json (hooks section).claude-hooks.json (in any directory)plugin-dir/hooks/hooks.jsonJSON configuration file.
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "bash command to execute"
}
]
}
]
}
}
PreToolUse: Before a tool runs
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{"type": "command", "command": "bash validate.sh"}]
}
]
}
}
PostToolUse: After a tool completes successfully
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{"type": "command", "command": "bash format.sh"}]
}
]
}
}
UserPromptSubmit: When user submits a prompt
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [{"type": "command", "command": "bash log-prompt.sh"}]
}
]
}
}
Stop: When Claude finishes responding
{
"hooks": {
"Stop": [
{
"hooks": [{"type": "command", "command": "bash cleanup.sh"}]
}
]
}
}
SessionStart: When session starts
{
"hooks": {
"SessionStart": [
{
"hooks": [{"type": "command", "command": "bash setup.sh"}]
}
]
}
}
Other Events:
For PreToolUse and PostToolUse events:
| Pattern | Matches | Example |
|---------|---------|---------|
| "Write" | Exact tool name | Matches only Write tool |
| "Edit\|Write" | Regex OR | Matches Edit or Write |
| "Bash" | Single tool | Matches Bash tool |
| "*" | Wildcard | Matches ALL tools |
| "Notebook.*" | Regex pattern | Matches NotebookEdit, etc. |
| "" | Empty (for non-tool events) | For lifecycle events |
Execute a bash command:
{
"type": "command",
"command": "bash /path/to/script.sh"
}
Use for:
Use LLM for evaluation:
{
"type": "prompt",
"prompt": "Analyze the tool usage and determine if it's safe"
}
Use for:
Hooks can return structured JSON to control behavior:
{
"continue": true,
"decision": "approve",
"reason": "Explanation for the decision",
"suppressOutput": false,
"systemMessage": "Optional message shown to user",
"hookSpecificOutput": {
"permissionDecision": "approve",
"permissionDecisionReason": "Safe operation",
"additionalContext": "Extra context for Claude"
}
}
continue: true to proceed, false to stopdecision: "approve", "block", or "warn"reason: Explanation for the decisionsuppressOutput: Hide hook output from transcriptsystemMessage: Message displayed to userpermissionDecision: For tool permission hooksadditionalContext: Context added to Claude's knowledge0: Success (stdout shown in transcript mode)2: Blocking error (stderr fed to Claude)Validate tool usage before execution:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash /path/to/validate-write.sh"
}
]
}
]
}
}
Example validate-write.sh:
#!/bin/bash
# Check if writing to protected directory
FILE_PATH="$1"
if [[ "$FILE_PATH" == /protected/* ]]; then
echo '{"decision": "block", "reason": "Cannot write to protected directory"}'
exit 2
fi
echo '{"decision": "approve", "reason": "Path is valid"}'
exit 0
Auto-format files after writing:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash /path/to/format-file.sh"
}
]
}
]
}
}
Example format-file.sh:
#!/bin/bash
FILE_PATH="$1"
if [[ "$FILE_PATH" == *.py ]]; then
black "$FILE_PATH"
elif [[ "$FILE_PATH" == *.js ]]; then
prettier --write "$FILE_PATH"
fi
exit 0
Log all tool usage:
{
"hooks": {
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash /path/to/log-tool.sh"
}
]
}
]
}
}
Validate bash commands for security:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash /path/to/validate-bash.sh"
}
]
}
]
}
}
Example validate-bash.sh:
#!/bin/bash
COMMAND="$1"
# Block dangerous commands
if echo "$COMMAND" | grep -qE "rm -rf /|dd if="; then
echo '{"decision": "block", "reason": "Dangerous command detected"}'
exit 2
fi
echo '{"decision": "approve"}'
exit 0
Initialize environment on session start:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash /path/to/setup-session.sh"
}
]
}
]
}
}
Example setup-session.sh:
#!/bin/bash
# Load environment, start services, etc.
export PROJECT_ROOT=$(pwd)
echo "Session initialized for project: $PROJECT_ROOT"
exit 0
Ask the user:
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "bash /path/to/script.sh"
}
]
}
]
}
}
.claude/This skill includes a validation script:
Python script for validating hooks.json files.
Usage:
python3 {baseDir}/scripts/validate-hooks.py <hooks.json>
What It Checks:
Returns:
Example:
python3 validate-hooks.py .claude/hooks.json
✅ Hooks validation passed
Events configured: PreToolUse, PostToolUse
Total hooks: 3
Scripts verified: 2
Hooks receive context as arguments:
PreToolUse / PostToolUse:
$1: Tool name$2: Tool parameters (JSON)UserPromptSubmit:
$1: User prompt textOther events:
Always return well-formed JSON:
#!/bin/bash
# Success
echo '{"decision": "approve", "reason": "Validation passed"}'
exit 0
# Block
echo '{"decision": "block", "reason": "Security violation detected"}'
exit 2
# Warn
echo '{"decision": "warn", "reason": "Unusual pattern detected"}'
exit 0
#!/bin/bash
if [ $# -lt 1 ]; then
echo '{"decision": "block", "reason": "Missing required arguments"}' >&2
exit 2
fi
# Validate input
if ! validate_input "$1"; then
echo '{"decision": "block", "reason": "Invalid input"}' >&2
exit 2
fi
# Normal processing
echo '{"decision": "approve"}'
exit 0
When creating hooks:
Bad (Command Injection):
eval "$1" # NEVER DO THIS
Good (Safe Validation):
if [[ "$1" =~ ^[a-zA-Z0-9_/-]+$ ]]; then
# Process sanitized input
fi
Before deploying hooks, verify:
Full templates and examples are available at:
{baseDir}/templates/hooks-template.json - Basic hooks configuration{baseDir}/templates/validation-script.sh - Validation hook script{baseDir}/templates/formatting-script.sh - Formatting hook script{baseDir}/references/hook-examples.md - Real-world exampleshooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/hooks/protect-dirs.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/hooks/auto-format.sh"
}
]
}
]
}
}
protect-dirs.sh:
#!/bin/bash
TOOL_NAME="$1"
FILE_PATH="$2"
PROTECTED_DIRS=("/etc" "/usr" "/sys" "/protected")
for dir in "${PROTECTED_DIRS[@]}"; do
if [[ "$FILE_PATH" == $dir/* ]]; then
echo "{\"decision\": \"block\", \"reason\": \"Cannot modify protected directory: $dir\"}"
exit 2
fi
done
echo '{"decision": "approve"}'
exit 0
auto-format.sh:
#!/bin/bash
FILE_PATH="$2"
if [[ "$FILE_PATH" == *.py ]]; then
black --quiet "$FILE_PATH" 2>/dev/null
elif [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.ts ]]; then
prettier --write "$FILE_PATH" > /dev/null 2>&1
fi
echo '{"decision": "approve", "reason": "File formatted"}'
exit 0
When the user asks to create hooks:
Be proactive in:
Your goal is to help users create secure, reliable event hooks that automate workflows and enforce policies effectively.
Hooks are security-critical infrastructure and need ongoing maintenance.
Never Trust Input: All parameters are potentially malicious
# WRONG
eval "$1"
# RIGHT
if [[ "$1" =~ ^[a-zA-Z0-9_/-]+$ ]]; then
# Safe to use
fi
Validate Everything: Check parameters, paths, commands
set -euo pipefail # Strict error handling
[[ ! "$PATH" =~ \.\. ]] # No directory traversal
Use Safe Defaults: Block by default, approve explicitly
echo '{"decision": "block", "reason": "Validation failed"}' >&2
exit 2
Block Dangerous Patterns:
eval, command substitution without validationrm -rf /, dd if=, mkfsWhen reviewing hooks for updates:
Problem: Hook script not running when expected Solutions:
chmod +x script.shProblem: Hook lacks input validation Solution: Add parameter validation at start of script:
#!/bin/bash
set -euo pipefail
# Validate input
if [[ ! "$1" =~ ^[a-zA-Z0-9_/-]+$ ]]; then
echo '{"decision": "block", "reason": "Invalid input"}'
exit 2
fi
Problem: Need to move from PostToolUse to PreToolUse Solution: Edit hooks.json to change the event key:
{
"hooks": {
"PreToolUse": [...] // Changed from PostToolUse
}
}
"Write|Edit" instead of "*"development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.