Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
laurigates avatar

Hooks Configuration

  • 85 installs
  • 49 repo stars
  • Updated August 4, 2026
  • laurigates/claude-plugins

Helps with ai & agent building tasks.

About

hooks-configuration is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • hooks-configuration
  • AI & Agent Building
  • AI-coding skill

Hooks Configuration by the numbers

  • 85 all-time installs (skills.sh)
  • Ranked #5,069 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/laurigates/claude-plugins --skill hooks-configuration

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs85
repo stars49
Last updatedAugust 4, 2026
Repositorylaurigates/claude-plugins

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

Claude Code Hooks Configuration

Expert knowledge for configuring and developing Claude Code hooks to automate workflows and enforce best practices.

When to Use This Skill

Use this skill when...Use something else when...
Configuring hook lifecycle events (PreToolUse, PostToolUse, etc.)Writing general shell scripts unrelated to hooks
Blocking dangerous commands or enforcing patternsSetting up CI/CD pipelines (use CI tooling)
Auto-formatting files after editsConfiguring Claude Code settings unrelated to hooks
Injecting context at session or subagent startWriting standalone automation scripts
Setting up PermissionRequest auto-approve/denyManaging project permissions via settings.json directly
Developing prompt or agent hooks for judgment-based decisionsBuilding MCP servers or custom tool integrations

Core Concepts

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?

  • Enforce code formatting automatically
  • Block dangerous commands before execution
  • Inject context at session start
  • Log commands for audit trails
  • Send notifications when tasks complete

Hook Lifecycle Events

EventWhen It FiresKey Use Cases
SessionStartSession begins/resumesEnvironment setup, context loading
SessionEndSession terminatesCleanup, state persistence
UserPromptSubmitUser submits promptInput validation, context injection
PreToolUseBefore tool executionPermission control, blocking dangerous ops
PostToolUseAfter tool completesAuto-formatting, logging, validation
PostToolUseFailureAfter tool execution failsRetry decisions, error handling
PermissionRequestClaude requests permission for a toolAuto approve/deny without user prompt
StopMain agent finishes respondingNotifications, git reminders
SubagentStartSubagent (Task tool) is about to startInput modification, context injection
SubagentStopSubagent finishesPer-task completion evaluation
WorktreeCreateNew git worktree created via EnterWorktreeWorktree setup, dependency install
WorktreeRemoveWorktree removed after session exitsCleanup, uncommitted changes alert
TeammateIdleTeammate in agent team goes idleAssign additional tasks to teammate
TaskCompletedTask in shared task list marked completeValidation gates before task acceptance
PreCompactBefore context compactionTranscript backup
NotificationClaude sends notificationCustom alerts
ConfigChangeClaude Code settings change at runtimeAudit config changes, validation
Stop vs SubagentStop: Stop fires at the session level when the main agent finishes a response turn. SubagentStop fires when an individual subagent (spawned via the Task tool) completes. Use Stop for session-level notifications; use SubagentStop for per-task quality gates.

For full schemas, examples, and timeout recommendations for each event, see .claude/rules/hooks-reference.md.

Configuration

File Locations

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.

Frontmatter Hooks (Skills and Commands)

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
---

Basic Structure

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Matcher Patterns

  • Exact match: "Bash" - matches exactly "Bash" tool
  • Regex patterns: "Edit|Write" - matches either tool
  • Wildcards: "Notebook.*" - matches tools starting with "Notebook"
  • All tools: "*" - matches everything
  • MCP tools: "mcp__server__tool" - targets MCP server tools

Input/Output Schema Summary

Hooks receive JSON via stdin with common fields (session_id, transcript_path, cwd, permission_mode, hook_event_name). Event-specific fields include tool_name and tool_input for PreToolUse, plus tool_response for PostToolUse, and subagent_type/subagent_prompt for SubagentStart.

Exit codes: 0 = allow, 2 = block (stderr shown to Claude), other = non-blocking error.

JSON responses vary by event: PreToolUse uses hookSpecificOutput with permissionDecision; Stop/SubagentStop use decision/reason; SubagentStart uses updatedPrompt; SessionStart uses hookSpecificOutput with additionalContext.

For detailed hook schemas and examples, see REFERENCE.md.

Common Hook Patterns

Block Dangerous Commands (PreToolUse)

#!/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

Auto-Format After Edits (PostToolUse)

#!/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

Remind About Built-in Tools (PreToolUse)

#!/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

Load Context at Session Start (SessionStart)

#!/bin/bash
GIT_STATUS=$(git status --short 2>/dev/null | head -5)
BRANCH=$(git branch --show-current 2>/dev/null)

CONTEXT="Current branch: $BRANCH\nPending changes:\n$GIT_STATUS"
jq -n --arg ctx "$CONTEXT" '{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": $ctx
  }
}'

For additional patterns (subagent injection, desktop notifications, audit logging, auto-approve, worktree setup, task gating), see REFERENCE.md.

Prompt-Based and Agent-Based Hooks

Four hook types: command (shell script, exit code), http (HTTPS endpoint), prompt (single-turn LLM call), and agent (multi-turn with tool access). Use command for deterministic rules; prompt/agent for judgment-based decisions. Add async: true for fire-and-forget; once: true to run only once per session.

Prompt and agent hooks work on PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, Stop, SubagentStop, TaskCompleted, UserPromptSubmit. All other events support command hooks only.

For hook type details, CLAUDE_ENV_FILE, and configuration examples, see REFERENCE.md and .claude/rules/prompt-agent-hooks.md.

Handling Blocked Commands

When a PreToolUse hook blocks a command:

SituationAction
Hook suggests alternativeUse the suggested tool/approach
Alternative won't workAsk user to run command manually
User says "proceed"Still blocked - explain and provide command for manual execution

Critical: User permission does NOT bypass hooks. Retrying a blocked command will fail again.

When command is legitimately needed:

1. Explain why the command is required 2. Describe alternatives considered and why they won't work 3. Provide exact command for user to run manually 4. Let user decide

Timeout Guidelines

The default hook timeout is 600s (10 minutes) since Claude Code 2.1.50. Set explicit timeouts to document intent and prevent "Hook cancelled" errors:

Hook TypeRecommended TimeoutUse Case
SessionStart120–300sTests, linters, dependency checks
SessionEnd60–120sLogging, cleanup, state saving
Stop / SubagentStop30–60sGit status checks, quick validations
PreToolUse10–30sQuick validations
PostToolUse30–120sLogging, notifications
PermissionRequest5–15sKeep fast for good UX

Background Subshell Pattern (Recommended for Slow Hooks)

When a hook needs to do slow work (logging, API calls) without blocking, run it in a background subshell:

#!/bin/bash
# Exits instantly; slow work continues in background
(
  echo "$(date): Session ended" >> ~/.claude/session.log
  # Any other slow work...
) &>/dev/null &
exit 0

Why this works: ( ) creates a subshell, & runs it in background, &>/dev/null prevents stdout/stderr from blocking, exit 0 returns success immediately.

Best Practices

AreaKey Points
ScriptRead stdin with cat; parse with jq; quote all vars; exit 2 to block, 0 to allow; stderr for messages; keep < 5s
Config$CLAUDE_PROJECT_DIR for portable paths; explicit timeouts; specific matchers over wildcards; test before enabling
SecurityValidate all inputs; use absolute paths; avoid .env / .git/ directly; review before deploy

Debugging

ErrorCauseFix
Hook cancelledTimeout exceededAdd "timeout" field or use background subshell pattern
Hook failedScript errorCheck exit code; add error handling
Command not foundMissing scriptVerify script path and permissions
Permission deniedScript not executablechmod +x ~/.claude/script.sh

Use /hooks to verify registration, claude --debug for verbose logging, and echo '{"tool_input":{"command":"..."}}' | bash your-hook.sh to test manually. Check $? for exit code. See hooks/README.md for plugin hook documentation.

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.