Claude Code Kit

Claude Code Hooks Generator

Pick an event, set a matcher, write the command. The settings.json block updates as you go. Everything runs in this tab.

Hook

Added

    settings.json

    Merge the "hooks" key into your existing settings file. Do not replace the whole file. Handler type is command here; the docs also list http, mcp_tool, prompt and agent handlers.

    10 examples you can load

    Each button adds the hook to the generator above. Read the command before you keep it.

    ExampleEvent and matcherNeeds
    Block rm -rf
    Exit code 2 from a PreToolUse hook blocks the call and feeds stderr back to Claude.
    PreToolUse Bashjq
    Protect .env files
    Stops Read, Edit and Write on .env and .env.* files. A Read deny rule in permissions does the same without a script; use this when you want a custom message.
    PreToolUse Read|Edit|Writejq
    Prettier after Edit and Write
    Formats the file Claude just changed. PostToolUse cannot block, so a Prettier failure never stops the session.
    PostToolUse Edit|Writejq, npx, Prettier in the project
    macOS notification when Claude needs you
    The Notification event fires on permission prompts and idle prompts.
    NotificationmacOS (osascript)
    macOS notification when Claude finishes
    Stop fires when Claude finishes responding. Do not exit 2 here unless you want Claude to keep going.
    StopmacOS (osascript)
    Log every Bash command
    Appends each command to a file you can audit later.
    PreToolUse Bashjq
    Block git push --force
    Uses the handler-level if field so the script only runs for matching Bash calls.
    PreToolUse Bashnone
    Add git status to session context
    SessionStart hooks can return hookSpecificOutput.additionalContext as JSON on stdout.
    SessionStart startup|resumejq, git
    Type-check after TypeScript edits
    The if field limits the hook to .ts files. Output goes to the transcript; PostToolUse cannot block.
    PostToolUse Edit|WriteTypeScript in the project
    Back up the transcript before compaction
    transcript_path is a common input field. Copy it before PreCompact runs so you keep the full history.
    PreCompactjq

    How a hook runs

    When an event fires, Claude Code looks up the groups registered for it, filters them by matcher, and runs each handler. A command handler gets the event as JSON on stdin. Its exit code and output tell Claude Code what to do next.

    The shape of the JSON

    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [
              { "type": "command", "command": "./check.sh", "timeout": 30 }
            ]
          }
        ]
      }
    }

    Events map to an array of groups. Each group has an optional matcher and a hooks array of handlers. Optional handler fields listed in the docs include if, timeout, statusMessage, async and once.

    Events and what the matcher compares

    EventMatcher comparesExit code 2
    SessionStartHow the session started: startup, resume, clear, compact, forkNo effect (stderr is shown, the action is not blocked)
    SetupCLI flag that triggered setup: init, maintenanceNo effect (stderr is shown, the action is not blocked)
    UserPromptSubmitNo matcherBlocks the prompt
    UserPromptExpansionCommand or skill name: your skill nameBlocks the expansion
    PreToolUsetool_name: Bash, Edit|Write, mcp__memory__.*Blocks the tool call
    PermissionRequesttool_name: Bash, Edit|WriteNo effect (stderr is shown, the action is not blocked)
    PermissionDeniedtool_name: BashNo effect (stderr is shown, the action is not blocked)
    PostToolUsetool_name: Edit|WriteNo effect (stderr is shown, the action is not blocked)
    PostToolUseFailuretool_name: BashNo effect (stderr is shown, the action is not blocked)
    PostToolBatchNo matcherStops the agentic loop
    NotificationNotification type: permission_prompt, idle_prompt, auth_success, elicitation_dialogNo effect (stderr is shown, the action is not blocked)
    MessageDisplayNo matcherNo effect (stderr is shown, the action is not blocked)
    SubagentStartAgent type: general-purpose, Explore, Plan, or a custom agent nameNo effect (stderr is shown, the action is not blocked)
    SubagentStopAgent type: general-purpose, Explore, Plan, or a custom agent namePrevents the subagent from stopping
    TaskCreatedNo matcherRolls back task creation
    TaskCompletedNo matcherPrevents completion
    StopNo matcherPrevents Claude from stopping
    StopFailureAPI error type: rate_limit, overloaded, authentication_failed, billing_errorNo effect (stderr is shown, the action is not blocked)
    TeammateIdleNo matcherPrevents the teammate from going idle
    InstructionsLoadedLoad reason: session_start, nested_traversal, path_glob_match, include, compactNo effect (stderr is shown, the action is not blocked)
    ConfigChangeConfig source: user_settings, project_settings, local_settings, policy_settings, skillsBlocks the config change
    CwdChangedNo matcherNo effect (stderr is shown, the action is not blocked)
    DirectoryAddedHow the directory was added: slash_command, register_repo_rootNo effect (stderr is shown, the action is not blocked)
    FileChangedLiteral file names to watch: .envrc|.envNo effect (stderr is shown, the action is not blocked)
    WorktreeCreateNo matcherAny non-zero exit fails creation
    WorktreeRemoveNo matcherAny non-zero exit fails removal if the directory exists
    PreCompactCompaction trigger: manual, autoBlocks compaction
    PostCompactCompaction trigger: manual, autoNo effect (stderr is shown, the action is not blocked)
    PreModelSwitchTarget model name: claude-opus-5, .*opus.*Blocks the model switch
    PostModelSwitchTarget model name: .*opus.*No effect (stderr is shown, the action is not blocked)
    ElicitationMCP server name: your server nameDeclines the request
    ElicitationResultMCP server name: your server nameBlocks the response
    SessionEndEnd reason: clear, resume, logout, prompt_input_exit, otherNo effect (stderr is shown, the action is not blocked)

    Checked against code.claude.com/docs/en/hooks on 2026-10-20. The docs change often, so confirm the event you depend on. unverified: whether SessionEnd blocks nothing in every version; treat it as informational.

    Pitfalls

    FAQ

    Where do Claude Code hooks go?

    In the hooks key of a settings file: ~/.claude/settings.json for all projects, .claude/settings.json for a shared project, or .claude/settings.local.json for your own uncommitted overrides.

    How do I block a tool call with a hook?

    Use a PreToolUse hook and exit with code 2. Whatever the script writes to stderr is fed back to Claude as the reason. You can also print JSON with hookSpecificOutput.permissionDecision set to deny.

    Which hook events can block?

    UserPromptSubmit, PreToolUse, Stop, SubagentStop, PreCompact, and several others can block with exit code 2. PostToolUse, Notification, SessionStart, SessionEnd and StopFailure cannot: the action already happened or the event is informational.

    What does the matcher do?

    The matcher filters when a group fires. For tool events it is compared with the tool name (Bash, Edit|Write, mcp__server__.*). For other events it is compared with a different field, such as the session start source. Events like UserPromptSubmit and Stop have no matcher.

    What does a hook receive?

    A JSON object on stdin with fields such as session_id, transcript_path, cwd, hook_event_name, and event-specific fields like tool_name and tool_input. Read it with jq in a shell command.