brainstorming
Structured design dialogue that validates ideas before implementation begins.
hooks-configuration
Claude Code hooks configuration and development. Covers hook lifecycle events, configuration patterns, input/output schemas, and common automation use cases. Use when user mentions hooks, automation, PreToolUse, PostToolUse, SessionStart, SubagentStart, or needs to enforce consistent behavior in ...
Full skill instructions
Expert knowledge for configuring and developing Claude Code hooks to automate workflows and enforce best practices.
What Are Hooks? Hooks are user-defined shell commands that execute at specific points in Claude Code's lifecycle. Unlike relying on Claude to "decide" to run something, hooks provide deterministic, guaranteed execution.
Why Use Hooks?
| Event | When It Fires | Key Use Cases |
|---|---|---|
| SessionStart | Session begins/resumes | Environment setup, context loading |
| UserPromptSubmit | User submits prompt | Input validation, context injection |
| PreToolUse | Before tool execution | Permission control, blocking dangerous ops |
| PostToolUse | After tool completes | Auto-formatting, logging, validation |
| Stop | Agent finishes | Notifications, git reminders |
| SubagentStart | Subagent is about to start | Input modification, context injection |
| SubagentStop | Subagent finishes | Task completion evaluation |
| PreCompact | Before context compaction | Transcript backup |
| Notification | Claude sends notification | Custom alerts |
| SessionEnd | Session terminates | Cleanup, state persistence |
Hooks are configured in settings files:
~/.claude/settings.json - User-level (applies everywhere).claude/settings.json - Project-level (committed to repo).claude/settings.local.json - Local project (not committed)Claude Code merges all matching hooks from all files.
Hooks can also be defined directly in skill and command frontmatter using the hooks field:
---
name: my-skill
description: A skill with hooks
allowed-tools: Bash, Read
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "echo 'Pre-tool hook from skill'"
timeout: 10
---
This allows skills and commands to define their own hooks that are active only when that skill/command is in use.
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here",
"timeout": 30
}
]
}
]
}
}
"Bash" - matches exactly "Bash" tool"Edit|Write" - matches either tool"Notebook.*" - matches tools starting with "Notebook""*" - matches everything"mcp__server__tool" - targets MCP server toolsHooks receive JSON via stdin with these common fields:
{
"session_id": "unique-session-id",
"transcript_path": "/path/to/conversation.json",
"cwd": "/current/working/directory",
"permission_mode": "mode",
"hook_event_name": "PreToolUse"
}
PreToolUse additional fields:
{
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}
PostToolUse additional fields:
{
"tool_name": "Bash",
"tool_input": { ... },
"tool_response": { ... }
}
SubagentStart additional fields:
{
"subagent_type": "Explore",
"subagent_prompt": "original prompt text",
"subagent_model": "claude-sonnet-4-20250514"
}
PreToolUse:
{
"permissionDecision": "allow|deny|ask",
"permissionDecisionReason": "explanation",
"updatedInput": { "modified": "input" }
}
Stop/SubagentStop:
{
"decision": "block",
"reason": "required explanation for continuing"
}
SubagentStart (input modification):
{
"updatedPrompt": "modified prompt text to inject context or modify behavior"
}
SessionStart:
{
"additionalContext": "Information to inject into session"
}
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Block rm -rf /
if echo "$COMMAND" | grep -Eq 'rm\s+(-rf|-fr)\s+/'; then
echo "BLOCKED: Refusing to run destructive command on root" >&2
exit 2
fi
exit 0
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *.py ]]; then
ruff format "$FILE" 2>/dev/null
ruff check --fix "$FILE" 2>/dev/null
elif [[ "$FILE" == *.ts ]] || [[ "$FILE" == *.tsx ]]; then
prettier --write "$FILE" 2>/dev/null
fi
exit 0
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -Eq '^\s*cat\s+[^|><]'; then
echo "REMINDER: Use the Read tool instead of 'cat'" >&2
exit 2
fi
exit 0
#!/bin/bash
GIT_STATUS=$(git status --short 2>/dev/null | head -5)
BRANCH=$(git branch --show-current 2>/dev/null)
cat << EOF
{
"additionalContext": "Current branch: $BRANCH\nPending changes:\n$GIT_STATUS"
}
EOF
#!/bin/bash
INPUT=$(cat)
SUBAGENT_TYPE=$(echo "$INPUT" | jq -r '.subagent_type // empty')
ORIGINAL_PROMPT=$(echo "$INPUT" | jq -r '.subagent_prompt // empty')
# Add project context to Explore agents
if [ "$SUBAGENT_TYPE" = "Explore" ]; then
PROJECT_INFO="Project uses TypeScript with Bun. Main source in src/."
cat << EOF
{
"updatedPrompt": "$PROJECT_INFO\n\n$ORIGINAL_PROMPT"
}
EOF
fi
exit 0
#!/bin/bash
# Linux
notify-send "Claude Code" "Task completed" 2>/dev/null
# macOS
osascript -e 'display notification "Task completed" with title "Claude Code"' 2>/dev/null
exit 0
#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // "N/A"')
echo "$(date -Iseconds) | $TOOL | $COMMAND" >> ~/.claude/audit.log
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash $CLAUDE_PROJECT_DIR/hooks-plugin/hooks/bash-antipatterns.sh",
"timeout": 5
}
]
}
]
}
}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'FILE=$(cat | jq -r \".tool_input.file_path\"); [[ \"$FILE\" == *.py ]] && ruff format \"$FILE\"'"
}
]
}
]
}
}
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash -c 'changes=$(git status --porcelain | wc -l); [ $changes -gt 0 ] && echo \"Reminder: $changes uncommitted changes\"'"
}
]
}
]
}
}
Script Development:
catjq for JSON parsingConfiguration:
$CLAUDE_PROJECT_DIR for portable pathsSecurity:
.env or .git/ directlyVerify hook registration:
/hooks
Enable debug logging:
claude --debug
Test hooks manually:
echo '{"tool_input": {"command": "cat file.txt"}}' | bash your-hook.sh
echo $? # Check exit code
See hooks/README.md for full documentation.
Structured design dialogue that validates ideas before implementation begins.
Comprehensive design intelligence for web and mobile UI/UX across 10 technology stacks.
Comprehensive implementation plans for multi-step tasks, breaking down specs into bite-sized, testable steps.
Introduction to the obra skills system with mandatory skill invocation rules and best practices.
Execute a written implementation plan with critical review and task checkpoints.
Delegate independent tasks to specialized agents working concurrently with isolated context.
Isolated git worktrees with smart directory selection and safety verification.
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
Plan searchable and shareable content that drives traffic, builds authority, and generates leads.
README-first repository scanner that extracts commands and classifies reproduction candidates without executing them.
Brainstorm and prioritize marketing strategies tailored to your SaaS stage, budget, and goals.
Plan and optimize your website's page hierarchy, navigation, URL structure, and internal linking.
The world's fastest calendar for remote work
Capture, organize, and utilize your knowledge effortlessly.
Instant Summaries of Audio & Video Interviews with AnySummary
Transform PDFs into engaging mind maps.
Chat with any PDF instantly
Create an optimal daily plan using your voice
A productivity platform to centralize organizational knowledge and workflows with contextual AI assistance.
AskYourPDF Pricing Plans: Tailored to Your Needs