Claude
Skills
Sign in
Back

hooks-authoring-reference

Included with Lifetime
$97 forever

Comprehensive quick-reference for authoring Claude Code hooks. Use when creating new hooks for settings, plugins, or skill/agent frontmatter. Covers all 26 event types, four handler types (command/http/prompt/agent), JSON input/output formats, matcher semantics, decision control, exit codes, async hooks, environment variables, and troubleshooting patterns. Trigger when user says "create a hook", "add a hook", "hook reference", "what hooks are available", "how do hooks work", "hook schema", "hook events", or is authoring hooks.json for a plugin or settings file.

AI Agents

What this skill does


# Claude Code Hooks Authoring Reference

Use this reference when creating, editing, or debugging Claude Code hooks. This is a distilled quick-reference from the official documentation.

## Hook Locations

| Location | Scope | Shareable |
|----------|-------|-----------|
| `~/.claude/settings.json` | All projects | No |
| `.claude/settings.json` | Single project | Yes (commit to repo) |
| `.claude/settings.local.json` | Single project | No (gitignored) |
| Managed policy settings | Organization-wide | Yes (admin-controlled) |
| Plugin `hooks/hooks.json` | When plugin enabled | Yes (bundled) |
| Skill/agent frontmatter | While component active | Yes (in component file) |

## Schema Formats

### Settings Format (settings.json)

Event types directly under the `hooks` key:

```json
{
  "hooks": {
    "<EventName>": [
      {
        "matcher": "<regex|*|empty>",
        "hooks": [
          { "type": "command", "command": "...", "timeout": 60 }
        ]
      }
    ]
  }
}
```

### Plugin Format (hooks/hooks.json)

Wrapper object with required `hooks` key and optional `description`:

```json
{
  "description": "Optional description",
  "hooks": {
    "<EventName>": [
      {
        "matcher": "<regex|*|empty>",
        "hooks": [
          { "type": "command", "command": "...", "timeout": 60 }
        ]
      }
    ]
  }
}
```

**Critical**: `hooks/hooks.json` is auto-discovered. Do NOT add `"hooks": "./hooks/hooks.json"` to `plugin.json` — it causes "Duplicate hooks file detected".

### Skill/Agent Frontmatter Format

```yaml
---
name: my-skill
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate.sh"
---
```

For subagents, `Stop` hooks are automatically converted to `SubagentStop`.

## All 26 Hook Events

### Session Lifecycle

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `SessionStart` | Session begins/resumes | No | `startup`, `resume`, `clear`, `compact` | `command` only |
| `SessionEnd` | Session terminates | No | `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` | `command`, `http` |
| `InstructionsLoaded` | CLAUDE.md or rules loaded | No | `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact` | `command`, `http` |
| `ConfigChange` | Config file changes | Yes | `user_settings`, `project_settings`, `local_settings`, `policy_settings`, `skills` | `command`, `http` |

### Agentic Loop

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `UserPromptSubmit` | User submits prompt | Yes | No matcher support | All four |
| `PreToolUse` | Before tool executes | Yes | Tool name (`Bash`, `Edit\|Write`, `mcp__.*`) | All four |
| `PermissionRequest` | Permission dialog shown | Yes | Tool name | All four |
| `PermissionDenied` | Auto mode denies tool | No (but can retry) | Tool name | `command`, `http` |
| `PostToolUse` | After tool succeeds | No (tool already ran) | Tool name | All four |
| `PostToolUseFailure` | After tool fails | No | Tool name | All four |
| `Stop` | Claude finishes responding | Yes | No matcher support | All four |
| `StopFailure` | Turn ends due to API error | No | `rate_limit`, `authentication_failed`, `billing_error`, `invalid_request`, `server_error`, `max_output_tokens`, `unknown` | `command`, `http` |

### Subagents & Tasks

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `SubagentStart` | Subagent spawned | No | Agent type (`Bash`, `Explore`, `Plan`, custom) | `command`, `http` |
| `SubagentStop` | Subagent finishes | Yes | Agent type | All four |
| `TaskCreated` | Task being created | Yes | No matcher support | All four |
| `TaskCompleted` | Task being completed | Yes | No matcher support | All four |
| `TeammateIdle` | Teammate going idle | Yes | No matcher support | `command`, `http` |

### Context & Compaction

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `PreCompact` | Before compaction | No | `manual`, `auto` | `command`, `http` |
| `PostCompact` | After compaction | No | `manual`, `auto` | `command`, `http` |

### File & Directory

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `CwdChanged` | Working directory changes | No | No matcher support | `command` only |
| `FileChanged` | Watched file changes | No | Filename basename (`.envrc`, `.env`) | `command` only |
| `Notification` | Claude sends notification | No | `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog` | `command`, `http` |

### Worktrees

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `WorktreeCreate` | Worktree being created | Yes (any non-zero) | No matcher support | `command`, `http` |
| `WorktreeRemove` | Worktree being removed | No | No matcher support | `command`, `http` |

### MCP Elicitation

| Event | When | Can Block? | Matcher Filters | Supported Types |
|-------|------|------------|-----------------|-----------------|
| `Elicitation` | MCP requests user input | Yes | MCP server name | `command`, `http` |
| `ElicitationResult` | User responds to elicitation | Yes | MCP server name | `command`, `http` |

## Four Handler Types

### Command (`type: "command"`)

```json
{ "type": "command", "command": "bash script.sh", "timeout": 60, "async": false, "shell": "bash" }
```

- Receives JSON on **stdin**, returns via **stdout/stderr + exit code**
- `async: true` runs in background, results delivered next turn
- `shell: "powershell"` for Windows PowerShell

### HTTP (`type: "http"`)

```json
{
  "type": "http",
  "url": "http://localhost:8080/hooks/event",
  "headers": { "Authorization": "Bearer $MY_TOKEN" },
  "allowedEnvVars": ["MY_TOKEN"],
  "timeout": 30
}
```

- POST with JSON body (same as command stdin)
- Response body uses same JSON output format as command hooks
- Non-2xx = non-blocking error. To block, return 2xx with decision JSON

### Prompt (`type: "prompt"`)

```json
{ "type": "prompt", "prompt": "Evaluate if safe: $ARGUMENTS", "model": "haiku", "timeout": 30 }
```

- Single-turn LLM evaluation. Returns `{"ok": true}` or `{"ok": false, "reason": "..."}`
- `$ARGUMENTS` placeholder for hook input JSON
- Not supported on: `SessionStart`, `CwdChanged`, `FileChanged`, and other command-only events

### Agent (`type: "agent"`)

```json
{ "type": "agent", "prompt": "Verify tests pass. $ARGUMENTS", "model": "haiku", "timeout": 60 }
```

- Multi-turn subagent with tool access (Read, Grep, Glob, etc.)
- Up to 50 turns. Same `{ok, reason}` response format
- Use when verification requires inspecting files or running commands

## Exit Codes (Command Hooks)

| Exit Code | Effect |
|-----------|--------|
| **0** | Success. Stdout parsed for JSON output. For `UserPromptSubmit`/`SessionStart`, stdout added as context |
| **2** | **Blocking error**. Stderr fed to Claude. JSON on stdout ignored |
| **Other** | Non-blocking error. Stderr logged in verbose mode (`Ctrl+O`). Execution continues |

**Important**: Only exit code 2 blocks. Exit code 1 is non-blocking (unlike typical Unix convention).

## Decision Control Per Event

| Events | Pattern | Key Fields |
|--------|---------|------------|
| `UserPromptSubmit`, `PostToolUse`, `PostToolUseFailure`, `Stop`, `SubagentStop`, `ConfigChange` | Top-level `decision` | `decision: "block"`, `reason` |
| `TeammateIdle`, `TaskCreated`, `TaskCompleted` | Exit code or `continue: false` | Exit 2 blocks with stderr feedback |
| `PreToolUse` | `hookSpecificOutput` | `permissionDecision` (allow/deny/ask/defer), `permissionDecisionReason`, `updatedInput`, `additionalContex

Related in AI Agents