Marketplace creating-hooks
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/brendanshields/creating-hooks" ~/.claude/skills/aiskillstore-marketplace-creating-hooks && rm -rf "$T"
manifest:
skills/brendanshields/creating-hooks/SKILL.mdsource content
Creating Hooks
Guides creation of Claude Code hooks for automation and workflow customization.
Quick Start
- Choose hook event (when should it trigger?)
- Configure in settings.json
- Create hook script
- Test the hook
Workflow: Create New Hook
Progress: - [ ] Select hook event - [ ] Add to settings.json - [ ] Create hook script - [ ] Test and validate
Step 1: Select Hook Event
| Event | When It Triggers | Common Use |
|---|---|---|
| Before tool runs | Block/modify tools |
| After tool succeeds | Validate, log, feedback |
| User sends message | Inject context, validate |
| Session begins | Load context, init state |
| Session ends | Cleanup, save state |
| Agent finishes | Decide if should continue |
Full event reference: reference.md
Step 2: Configure settings.json
Location priority (highest wins):
(local, not committed).claude/settings.local.json
(project).claude/settings.json
(user)~/.claude/settings.json
Basic structure:
{ "hooks": { "EventName": [ { "matcher": "ToolPattern", "hooks": [ { "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.sh\"" } ] } ] } }
Step 3: Create Hook Script
Use templates from templates/ directory.
Key requirements:
- Read JSON from stdin
- Use exit codes for control (0=success, 2=block)
- Output JSON for decisions
Step 4: Test
Run hook manually with test input:
echo '{"tool_name":"Write"}' | bash .claude/hooks/my-hook.sh
Hook Configuration
Matcher Patterns
"matcher": "Write" // Exact match "matcher": "Edit|Write" // Multiple tools "matcher": "mcp__.*" // MCP tools (regex) "matcher": "*" // All tools
Matchers apply to:
PreToolUse, PostToolUse, PermissionRequest
Timeout
{ "type": "command", "command": "...", "timeout": 120 }
Default: 60 seconds. Max recommended: 300 seconds.
Exit Codes
| Code | Meaning | Behavior |
|---|---|---|
| 0 | Success | Continue normally |
| 2 | Block | Stop action, show error |
| Other | Non-blocking error | Log only (verbose mode) |
JSON Output
Return JSON to stdout for decisions:
{ "decision": "block", "reason": "Why blocked", "additionalContext": "Info for Claude" }
Decision values by event:
:PreToolUse
,allow
,denyask
:PostToolUse
(with reason)block
:UserPromptSubmit
(with reason)block
:Stop
(requires reason)block
Security Best Practices
- Quote all variables:
not"$VAR"$VAR - Use absolute paths:
"$CLAUDE_PROJECT_DIR/..." - Validate inputs: Check before processing
- Block path traversal: Reject paths with
.. - Set timeouts: Prevent runaway scripts
Environment Variables
Available in all hooks:
- Project root pathCLAUDE_PROJECT_DIR
- "true" if web environmentCLAUDE_CODE_REMOTE
SessionStart only:
- Path to persist env varsCLAUDE_ENV_FILE
Common Patterns
Inject Context on Session Start
#!/bin/bash # Output context for Claude echo '{"additionalContext": "Project uses TypeScript"}' exit 0
Block Dangerous File Edits
#!/bin/bash INPUT=$(cat) FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') if [[ "$FILE" == *".env"* ]]; then echo "Blocking edit to sensitive file" >&2 exit 2 fi exit 0
Log All Tool Usage
#!/bin/bash INPUT=$(cat) TOOL=$(echo "$INPUT" | jq -r '.tool_name') echo "$(date -Iseconds) $TOOL" >> "$CLAUDE_PROJECT_DIR/.claude/tool.log" exit 0
See reference.md for complete event details and more examples.