# Hooks

> Learn how to customize and extend Claude Code's behavior by registering shell commands

Claude Code hooks are user-defined shell commands that execute at various points in Claude Code's lifecycle. Hooks provide deterministic control over Claude Code's behavior, ensuring certain actions always happen rather than relying on the LLM to choose to run them.

## Use Cases for Hooks

- **Notifications**: Customize how you get notified when Claude Code is awaiting your input
- **Automatic formatting**: Run `prettier` on .ts files, `gofmt` on .go files, etc. after every file edit
- **Logging**: Track and count all executed commands for compliance or debugging
- **Feedback**: Provide automated feedback when Claude Code produces code that doesn't follow conventions
- **Custom permissions**: Block modifications to production files or sensitive directories

By encoding these rules as hooks rather than prompting instructions, you turn suggestions into app-level code that executes every time.

## Security Considerations

**Important**: Hooks run automatically during the agent loop with your current environment's credentials. Malicious hooks code can exfiltrate your data. Always review your hooks implementation before registering them.

## Hook Events Overview

| Event               | When it fires                                                    |
| :------------------ | :--------------------------------------------------------------- |
| `PreToolUse`        | Before tool calls (can block them)                               |
| `PermissionRequest` | When a permission dialog is shown (can allow or deny)            |
| `PostToolUse`       | After tool calls complete                                        |
| `UserPromptSubmit`  | When the user submits a prompt, before Claude processes it       |
| `Notification`      | When Claude Code sends notifications                             |
| `Stop`              | When Claude Code finishes responding                             |
| `SubagentStop`      | When subagent tasks complete                                     |
| `PreCompact`        | Before Claude Code runs a compact operation                      |
| `Setup`             | When invoked with `--init`, `--init-only`, or `--maintenance`    |
| `SessionStart`      | When Claude Code starts or resumes a session                     |
| `SessionEnd`        | When Claude Code session ends                                    |

## Quickstart: Logging Bash Commands

### Step 1: Open Hooks Configuration
Run `/hooks` and select the `PreToolUse` hook event.

### Step 2: Add a Matcher
Select `+ Add new matcher...` and type `Bash` to run your hook only on Bash tool calls.

**Note**: Use `*` to match all tools.

### Step 3: Add the Hook
Enter this command:
```bash
jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt
```

### Step 4: Save Configuration
Select `User settings` for storage location (applies to all projects).

### Step 5: Verify
Check `~/.claude/settings.json`:
```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
          }
        ]
      }
    ]
  }
}
```

## Hook Configuration Format

### Basic Structure
```json
{
  "hooks": {
    "<EventName>": [
      {
        "matcher": "<pattern>",
        "hooks": [
          {
            "type": "command",
            "command": "<shell command>"
          }
        ]
      }
    ]
  }
}
```

### Matcher Patterns

| Pattern   | Matches                                    |
| :-------- | :----------------------------------------- |
| `*`       | All tools                                  |
| `Bash`    | Only Bash tool                             |
| `Write`   | Only Write tool                            |
| `Edit`    | Only Edit tool                             |
| `A\|B`    | Tool A or Tool B (e.g., `Write\|Edit`)     |

## Hook Input (via stdin)

Claude Code passes hook input as JSON via stdin. Example for `PreToolUse`:

```json
{
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test",
    "description": "Run the test suite"
  },
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.json",
  "cwd": "/current/working/directory"
}
```

## Exit Codes

| Exit Code | Behavior                                                           |
| :-------- | :----------------------------------------------------------------- |
| 0         | Success - continue normally                                        |
| 2         | Block the operation and feed stderr back to Claude                 |
| Other     | Error - logged but execution continues                             |

### Example: Blocking Write Operations

```bash
#!/bin/bash
# Block SQL write operations in db-reader subagent

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Block write operations (case-insensitive)
if echo "$COMMAND" | grep -iE '\b(INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE)\b' > /dev/null; then
  echo "Blocked: Write operations not allowed. Use SELECT queries only." >&2
  exit 2
fi

exit 0
```

## Common Hook Patterns

### Auto-Format After File Edits
```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $FILE"
          }
        ]
      }
    ]
  }
}
```

### Log All Tool Usage
```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{tool: .tool_name, time: now}' >> ~/.claude/tool-usage.log"
          }
        ]
      }
    ]
  }
}
```

### Validate Bash Commands
```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/validate-command.sh"
          }
        ]
      }
    ]
  }
}
```

### Custom Notifications
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

## Hooks in Subagents

### Hooks in Subagent Frontmatter

Define hooks that run only while a specific subagent is active:

```yaml
---
name: code-reviewer
description: Review code changes with automatic linting
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-command.sh $TOOL_INPUT"
  PostToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "./scripts/run-linter.sh"
---
```

### Project-Level Subagent Hooks

Configure hooks in `settings.json` for subagent lifecycle events:

```json
{
  "hooks": {
    "SubagentStart": [
      {
        "matcher": "db-agent",
        "hooks": [
          { "type": "command", "command": "./scripts/setup-db-connection.sh" }
        ]
      }
    ],
    "SubagentStop": [
      {
        "matcher": "db-agent",
        "hooks": [
          { "type": "command", "command": "./scripts/cleanup-db-connection.sh" }
        ]
      }
    ]
  }
}
```

## Environment Variables Available in Hooks

Hooks can access:
- `$FILE` - The file being edited (for Write/Edit tools)
- `$TOOL_INPUT` - The full tool input as JSON string
- Standard environment variables from your shell

## Grid Integration Opportunities

<!-- Placeholder for Grid-specific integration notes -->
