Files

16 KiB

Documentation Index

Fetch the complete documentation index at: https://vineetagarwal-code-claude-code.mintlify.app/llms.txt Use this file to discover all available pages before exploring further.

Hooks

Run shell commands, HTTP requests, or prompts automatically when Claude uses tools or reaches session milestones.

Hooks let you attach automation to Claude Code's tool lifecycle. When Claude reads a file, runs a bash command, or finishes a response, your configured hooks execute automatically. Use hooks to enforce code style, run tests, log tool usage, or gate what Claude is allowed to do.

How hooks work

A hook is a command (shell script, HTTP endpoint, or LLM prompt) bound to a specific event. When that event fires, Claude Code runs every matching hook and uses the exit code and output to decide what to do next.

The input to each hook is a JSON object on stdin describing what happened — for example, the tool name and its arguments for PreToolUse, or the tool name and response for PostToolUse.

Exit code semantics

Exit code behavior varies by event. The full table is documented in each event's description, but the general pattern is:

Exit code Meaning
0 Success. Stdout may be shown to Claude (event-specific).
2 Block or inject. Show stderr to Claude and (for PreToolUse) prevent the tool call.
Other Show stderr to the user only; execution continues.

Hook events

Fires before every tool call. The hook input contains the tool name and arguments as JSON.
* Exit `0`: tool proceeds normally (stdout not shown)
* Exit `2`: block the tool call and show stderr to Claude so it can respond
* Other: show stderr to the user but allow the tool call to continue

Use matchers to restrict this hook to specific tools (e.g., `Bash`, `Write`).
Fires after every successful tool call. The hook input contains `inputs` (the tool arguments) and `response` (the tool result).
* Exit `0`: stdout is shown in transcript mode (Ctrl+O)
* Exit `2`: show stderr to Claude immediately (Claude can respond)
* Other: show stderr to the user only

Use this to run formatters, linters, or test runners after file edits.
Fires when a tool call results in an error. Input contains `tool_name`, `tool_input`, `error`, `error_type`, `is_interrupt`, and `is_timeout`.
Same exit code semantics as `PostToolUse`.
Fires just before Claude's turn ends. No matcher support.
* Exit `0`: no output shown
* Exit `2`: show stderr to Claude and continue the conversation (Claude gets another turn)
* Other: show stderr to the user only

Use this to check that all required tasks are complete before Claude finishes.
Like `Stop`, but fires when a subagent (launched via the Agent tool) finishes. Input includes `agent_id`, `agent_type`, and `agent_transcript_path`. Same exit code semantics as `Stop`. Fires when a new subagent is launched. Input includes `agent_id` and `agent_type`.
* Exit `0`: stdout is shown to the subagent's initial prompt
* Other: show stderr to user only
Fires at the start of every session (startup, resume, `/clear`, or `/compact`). Input contains the start `source`.
* Exit `0`: stdout is shown to Claude
* Other: show stderr to user only (blocking errors are ignored)

Match on `source` values: `startup`, `resume`, `clear`, `compact`.
Fires when you press Enter to submit a prompt. Input contains your original prompt text.
* Exit `0`: stdout is shown to Claude (can prepend context)
* Exit `2`: block the prompt and show stderr to the user only
* Other: show stderr to user only
Fires before Claude Code compacts the conversation (auto or manual). Input contains compaction details.
* Exit `0`: stdout is appended as custom compact instructions
* Exit `2`: block the compaction
* Other: show stderr to user but proceed

Match on `trigger`: `manual` or `auto`.
Fires after compaction completes. Input contains compaction details and the summary.
* Exit `0`: stdout shown to user
* Other: show stderr to user only
Fires with `trigger: init` (project onboarding) or `trigger: maintenance` (periodic). Use this for one-time setup scripts or periodic maintenance tasks.
* Exit `0`: stdout shown to Claude
* Other: show stderr to user only
Fires when Claude Code would show a permission prompt. Output JSON with `hookSpecificOutput.decision` to approve or deny programmatically.
* Exit `0`: use the hook's decision if provided
* Other: show stderr to user only
Fires when the auto mode classifier denies a tool call. Return `{"hookSpecificOutput":{"hookEventName":"PermissionDenied","retry":true}}` to tell Claude it may retry. Fires for permission prompts, idle prompts, auth success, and elicitation events. Match on `notification_type`.
* Exit `0`: no output shown
* Other: show stderr to user only
Fires after the working directory changes. Input includes `old_cwd` and `new_cwd`. The `CLAUDE_ENV_FILE` environment variable is set — write bash export lines to that file to apply new env vars to subsequent Bash tool calls. Fires when a file matching the hook's `matcher` pattern changes on disk. The matcher specifies filename patterns to watch (e.g., `.envrc|.env`). Like `CwdChanged`, supports `CLAUDE_ENV_FILE` for injecting environment. Fires when the session is ending (clear, logout, or exit). Match on `reason`: `clear`, `logout`, `prompt_input_exit`, or `other`. Fires when settings files change during a session. Match on `source`: `user_settings`, `project_settings`, `local_settings`, `policy_settings`, or `skills`.
* Exit `0`: allow the change
* Exit `2`: block the change from being applied
Fires when any instruction file (CLAUDE.md or rule) is loaded. Observability-only — does not support blocking. `WorktreeCreate` fires when an isolated worktree needs to be created. Stdout should contain the absolute path of the created worktree. `WorktreeRemove` fires when a worktree should be cleaned up. `TaskCreated` and `TaskCompleted` fire when tasks are created or marked complete. Input includes `task_id`, `task_subject`, `task_description`, `teammate_name`, and `team_name`. Exit `2` prevents the state change. Fires before a teammate goes idle. Exit `2` to send stderr to the teammate and prevent it from going idle. `Elicitation` fires when an MCP server requests user input. Return JSON in `hookSpecificOutput` to provide the response programmatically. `ElicitationResult` fires after the user responds, allowing you to modify or block the response.

Configuring hooks

Run /hooks inside Claude Code to open the hooks configuration menu. The menu shows all configured hooks grouped by event and lets you add, edit, or remove them interactively.

Hooks are stored in the hooks field of settings files:

  • ~/.claude/settings.json — user-level hooks (apply everywhere)
  • .claude/settings.json — project-level hooks (apply for this project)
  • .claude/settings.local.json — local hooks (not checked into VCS)

Configuration format

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $CLAUDE_FILE_PATH"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Session complete' >> ~/.claude-log.txt"
          }
        ]
      }
    ]
  }
}

Each event maps to an array of matcher objects. Each matcher object has:

  • matcher (optional) — a string pattern to match against the event's matchable field (for example, tool_name for PreToolUse/PostToolUse, trigger for Setup, source for SessionStart)
  • hooks — an array of hook commands to run when the matcher matches

Hook command types

```json theme={null} { "type": "command", "command": "npm test", "timeout": 60, "shell": "bash" } ```
Fields:

* `command` — the shell command to run (required)
* `timeout` — timeout in seconds (default: no limit)
* `shell` — `"bash"` (default) or `"powershell"`
* `statusMessage` — custom spinner text shown while the hook runs
* `async` — run in background without blocking (`true`/`false`)
* `once` — run once and remove the hook automatically
* `if` — permission rule syntax to conditionally skip the hook (e.g., `"Bash(git *)"`)
```json theme={null} { "type": "http", "url": "https://hooks.example.com/claude-event", "headers": { "Authorization": "Bearer $MY_TOKEN" }, "allowedEnvVars": ["MY_TOKEN"], "timeout": 10 } ```
Claude Code POSTs the hook input JSON to the URL. Headers support `$VAR` expansion for variables listed in `allowedEnvVars`.
```json theme={null} { "type": "prompt", "prompt": "Review this tool call for security issues: $ARGUMENTS. If you find a problem, output an explanation and exit with code 2.", "model": "claude-haiku-4-5", "timeout": 30 } ```
The hook prompt is evaluated by an LLM. `$ARGUMENTS` is replaced with the hook input JSON. The LLM's response becomes the hook output.
```json theme={null} { "type": "agent", "prompt": "Verify that the unit tests in $ARGUMENTS passed and all assertions are meaningful.", "timeout": 60 } ```
Like a prompt hook, but runs as a full agent with tool access. Useful for verification tasks that require reading files or running commands.

Matcher patterns

For events that support matching (like PreToolUse, PostToolUse, SessionStart), the matcher field filters which inputs trigger the hook.

  • An empty or absent matcher matches all inputs for that event.
  • For tool events, the matcher is matched against the tool_name (e.g., "Bash", "Write", "Read").
  • For SessionStart, it matches source (e.g., "startup", "compact").
  • For Setup, it matches trigger (e.g., "init", "maintenance").
  • For FileChanged, the matcher specifies filename patterns to watch (e.g., ".envrc|.env").

Example hooks

Auto-format files after editing

Run Prettier after every file write:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

Run tests after bash commands

Run the test suite after any bash command that touches source files:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if git diff --name-only HEAD | grep -q '\\.ts$'; then npm test; fi",
            "timeout": 120,
            "async": true
          }
        ]
      }
    ]
  }
}

Log all tool usage

Append every tool call to a log file:

{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) $CLAUDE_TOOL_NAME\" >> ~/.claude-tool-log.txt",
            "async": true
          }
        ]
      }
    ]
  }
}

Block dangerous commands

Use PreToolUse to prevent rm -rf from being called:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -q 'rm -rf'; then echo 'Blocked: rm -rf is not allowed' >&2; exit 2; fi"
          }
        ]
      }
    ]
  }
}

Inject environment on directory change

Use CwdChanged with CLAUDE_ENV_FILE to load .envrc when you change directories:

{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "if [ -f .envrc ]; then grep '^export ' .envrc >> \"$CLAUDE_ENV_FILE\"; fi"
          }
        ]
      }
    ]
  }
}

Hook timeout configuration

Set a per-hook timeout in seconds using the timeout field:

{
  "type": "command",
  "command": "npm run integration-tests",
  "timeout": 300
}

Hooks without a timeout run until they exit naturally. For long-running hooks that should not block Claude, use "async": true.

Hooks vs. skills

Feature Hooks Skills
When they run Automatically on tool events When Claude or you explicitly invoke /skill-name
Purpose Side effects, gating, observability On-demand workflows and capabilities
Configuration Settings JSON Markdown files in .claude/skills/
Input JSON from the tool event The arguments you pass to the skill

Use hooks for things that should happen automatically every time (formatting, logging, enforcement). Use skills for repeatable workflows that you want to trigger on demand.

Built with Mintlify.