Skip to main content

claude-hooks

This skill should be used when creating hooks, automating workflows, or when "PreToolUse", "PostToolUse", "hooks.json", "event handler", or "create hook" are mentioned.

Jump to install

Source facts

Repository
outfitter-dev/agents
Last source activity
January 27, 2026 at 15:45
Detected SKILL.md language
English
Stars
28
Forks
1

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
9 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
claude-hooks
description
This skill should be used when creating hooks, automating workflows, or when "PreToolUse", "PostToolUse", "hooks.json", "event handler", or "create hook" are mentioned.
metadata
{"version":"2.0.0","related-skills":["claude-commands","claude-plugins","claude-agents","claude-config"]}
# Claude Hook Authoring Create event hooks that automate workflows, validate operations, and respond to Claude Code events. ## Hook Types Three hook execution types: | Type | Best For | Example | |------|----------|---------| | **command** | Deterministic checks, external tools, performance | Bash script validates paths | | **prompt** | Complex reasoning, context-aware validation | LLM evaluates if action is safe | | **agent** | Multi-step verification requiring tool access | Agent with Read/Grep tools verifies consistency | **Command hooks** (for deterministic/fast checks): ```json { "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh", "timeout": 10 } ``` **Prompt hooks** (recommended for complex logic): ```json { "type": "prompt", "prompt": "Evaluate if this file write is safe: $TOOL_INPUT. Check for sensitive paths, credentials, path traversal. Return 'allow' or 'deny' with reason.", "timeout": 30 } ``` **Agent hooks** (for complex multi-step verification): ```json { "type": "agent", "prompt": "Verify this code change maintains consistency with the existing codebase. Check imports, type signatures, and naming conventions. Use Read and Grep tools as needed.", "allowedTools": ["Read", "Grep", "Glob"], "timeout": 120 } ``` Agent hooks spawn a subagent with tool access for verification tasks that require reading files, searching code, or multi-step reasoning. Use when prompt hooks are insufficient. ## Hook Events | Event | When | Can Block | Common Uses | |-------|------|-----------|-------------| | **PreToolUse** | Before tool executes | Yes | Validate commands, check paths, enforce policies | | **PostToolUse** | After tool succeeds | No | Auto-format, run linters, update docs | | **PostToolUseFailure** | After tool fails | No | Error logging, retry logic, notifications | | **PermissionRequest** | Permission dialog shown | Yes | Auto-allow/deny based on rules | | **UserPromptSubmit** | User submits prompt | No | Add context, log activity, augment prompts | | **Notification** | Claude sends notification | No | External alerts, logging | | **Stop** | Main agent finishes | No | Cleanup, completion notifications | | **SubagentStart** | Subagent spawns | No | Track subagent usage | | **SubagentStop** | Subagent finishes | No | Log results, trigger follow-ups | | **Setup** | `--init`, `--init-only`, or `--maintenance` flags | No | Initialize environment, install dependencies | | **PreCompact** | Before context compacts | No | Backup conversation, preserve context | | **SessionStart** | Session starts/resumes | No | Load context, show status, init resources | | **SessionEnd** | Session ends | No | Cleanup, save state, log metrics | See [references/hook-types.md](references/hook-types.md) for detailed documentation of each event. ## Quick Start ### Auto-Format TypeScript ```json { "hooks": { "PostToolUse": [ { "matcher": "Write|Edit(*.ts|*.tsx)", "hooks": [{ "type": "command", "command": "biome check --write \"$file\"", "timeout": 10 }] } ] } } ``` ### Block Dangerous Commands ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-bash.sh", "timeout": 5 }] } ] } } ``` **validate-bash.sh**: ```bash #!/usr/bin/env bash set -euo pipefail INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty') if echo "$COMMAND" | grep -qE '\brm\s+-rf\s+/'; then echo "Dangerous command blocked: rm -rf /" >&2 exit 2 # Exit 2 = block and show error to Claude fi exit 0 ``` ### Smart Validation with Prompt Hook ```json { "hooks": { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [{ "type": "prompt", "prompt": "Analyze this file operation for safety. Check: 1) No sensitive paths (/etc, ~/.ssh), 2) No credentials in content, 3) No path traversal (..). Tool input: $TOOL_INPUT. Respond with JSON: {\"decision\": \"allow|deny\", \"reason\": \"...\"}", "timeout": 30 }] } ] } } ``` ## Configuration Locations | Location | Scope | Committed | |----------|-------|-----------| | `.claude/settings.json` | Project (team-shared) | Yes | | `.claude/settings.local.json` | Project (local only) | No | | `~/.claude/settings.json` | Personal (all projects) | No | | `plugin/hooks/hooks.json` | Plugin | Yes | ### Plugin Format (hooks.json) Uses wrapper structure: ```json { "description": "Plugin hooks for auto-formatting", "hooks": { "PostToolUse": [...] } } ``` ### Settings Format (settings.json) Direct structure (no wrapper): ```json { "hooks": { "PostToolUse": [...] } } ``` ## Matchers Matchers determine which tool invocations trigger the hook. Case-sensitive. ```json {"matcher": "Write"} // Exact match {"matcher": "Edit|Write"} // Multiple tools (OR) {"matcher": "*"} // All tools {"matcher": "Write(*.py)"} // File pattern {"matcher": "Write|Edit(*.ts|*.tsx)"} // Multiple + pattern {"matcher": "mcp__memory__.*"} // MCP server tools {"matcher": "mcp__github__create_issue"} // Specific MCP tool ``` **Lifecycle hooks** (SessionStart, SessionEnd, Stop, Notification) use special matchers: ```json // SessionStart matchers {"matcher": "startup"} // Initial start {"matcher": "resume"} // --resume or --continue {"matcher": "clear"} // After /clear {"matcher": "compact"} // After compaction // PreCompact matchers {"matcher": "manual"} // User triggered /compact {"matcher": "auto"} // Automatic compaction ``` See [references/matchers.md](references/matchers.md) for advanced patterns. ## Input Format All hooks receive JSON on stdin: ```json { "session_id": "abc123", "transcript_path": "/path/to/transcript.jsonl", "cwd": "/current/working/directory", "hook_event_name": "PreToolUse", "permission_mode": "ask", "tool_name": "Write", "tool_input": { "file_path": "/project/src/file.ts", "content": "export const foo = 'bar';" } } ``` **Event-specific fields**: - Tool hooks: `tool_name`, `tool_input`, `tool_result` (PostToolUse) - UserPromptSubmit: `user_prompt` - Stop/SubagentStop: `reason` **Prompt hooks** access fields via placeholders: - `$ARGUMENTS` - Full context passed to the hook (general-purpose) - `$TOOL_INPUT` - Tool input for tool-related events - `$TOOL_RESULT` - Tool result (PostToolUse only) - `$USER_PROMPT` - User prompt (UserPromptSubmit only) ### Reading Input **Bash**: ```bash #!/usr/bin/env bash set -euo pipefail INPUT=$(cat) TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name') FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') ``` **Bun/TypeScript**: ```typescript #!/usr/bin/env bun const input = await Bun.stdin.json(); const toolName = input.tool_name; const filePath = input.tool_input?.file_path; ``` ## Output Format ### Exit Codes (Simple) ```bash exit 0 # Success, continue execution exit 2 # Block operation (PreToolUse only), stderr shown to Claude exit 1 # Warning, stderr shown to user, continues ``` ### JSON Output (Advanced) ```json { "continue": true, "suppressOutput": false, "systemMessage": "Context for Claude", "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow|deny|ask", "permissionDecisionReason": "Explanation", "updatedInput": {"modified": "field"} } } ``` **PreToolUse** can modify tool input via `updatedInput` and control permissions via `permissionDecision`. ## Environment Variables | Variable | Availability | Description | |----------|--------------|-------------| | `$CLAUDE_PROJECT_DIR` | All hooks | Project root directory | | `$CLAUDE_PLUGIN_ROOT` | Plugin hooks | Plugin root (use for portable paths) | | `$file` | PostToolUse (Write/Edit) | Path to affected file | | `$CLAUDE_ENV_FILE` | SessionStart | Write env vars here to persist | | `$CLAUDE_CODE_REMOTE` | All hooks | Set if running in remote context | **Plugin hooks** should always use `${CLAUDE_PLUGIN_ROOT}` for portability: ```json { "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh" } ``` **SessionStart** can persist environment variables: ```bash #!/usr/bin/env bash # Persist variables for the session echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE" echo "export API_URL=https://api.example.com" >> "$CLAUDE_ENV_FILE" ``` ## Component-Scoped Hooks Skills, agents, and commands can define hooks in frontmatter. These hooks only run when the component is active. **Supported events**: PreToolUse, PostToolUse, Stop ### Skill with Hooks ```yaml --- name: my-skill description: Skill with validation hooks hooks: PreToolUse: - matcher: "Write|Edit" hooks: - type: prompt prompt: "Validate this write operation for the skill context..." --- ``` ### Agent with Hooks ```yaml --- name: security-reviewer model: sonnet hooks: PreToolUse: - matcher: "Bash" hooks: - type: command command: "${CLAUDE_PLUGIN_ROOT}/scripts/validate-bash.sh" Stop: - matcher: "*" hooks:
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub