# Hook Validation Checklist

Based on official Claude Code documentation: https://code.claude.com/docs/en/hooks

## Required

- [ ] Hook configuration is valid JSON
- [ ] Event name is a valid lifecycle event
- [ ] At least one hook handler defined per event entry

## Valid Lifecycle Events

| Event | When it fires | Matcher target |
|-------|---------------|----------------|
| `SessionStart` | Session begins/resumes | source: startup, resume, clear, compact |
| `UserPromptSubmit` | Before Claude processes prompt | - |
| `PreToolUse` | Before tool call | tool name |
| `PermissionRequest` | Permission dialog appears | tool name |
| `PostToolUse` | After successful tool call | tool name |
| `PostToolUseFailure` | After tool failure | tool name |
| `Notification` | Claude sends notification | type: permission_prompt, idle_prompt |
| `SubagentStart` | Subagent spawned | agent type name |
| `SubagentStop` | Subagent finishes | agent type name |
| `Stop` | Main agent finishes | - |
| `PreCompact` | Before context compaction | - |
| `SessionEnd` | Session ends | - |

## Hook Handler Validation

### Command type (`type: "command"`)
- [ ] `command` field is non-empty
- [ ] Referenced script/binary exists on filesystem
- [ ] Script is executable (Unix: chmod +x)
- [ ] Script handles JSON stdin correctly
- [ ] Exit codes are meaningful (0=continue, 2=block)
- [ ] `timeout` set if script might hang (default: varies)

### Prompt type (`type: "prompt"`)
- [ ] `prompt` field is non-empty and descriptive
- [ ] `model` is valid if specified (haiku recommended for speed)
- [ ] `timeout` set appropriately

### Agent type (`type: "agent"`)
- [ ] Agent configuration is valid
- [ ] Tools specified for the agent hook
- [ ] Timeout set to prevent runaway agents

## Matcher Validation

- [ ] Matcher is a valid regex pattern
- [ ] Matcher is specific enough (avoid `.*` unless intentional)
- [ ] For tool events: matches known tool names
- [ ] For SessionStart: matches valid sources
- [ ] For Notification: matches valid types
- [ ] For Subagent events: matches valid agent types

## Configuration Locations

| Location | Scope | Priority |
|----------|-------|----------|
| `~/.claude/settings.json` | User (all projects) | Low |
| `.claude/settings.json` | Project (shared) | Medium |
| `.claude/settings.local.json` | Personal (gitignored) | High |
| Skill frontmatter `hooks:` | Skill-scoped | Skill only |
| Agent frontmatter `hooks:` | Agent-scoped | Agent only |

## JSON Input Format (stdin to command hooks)

```json
{
  "session_id": "string",
  "transcript_path": "string",
  "cwd": "string",
  "permission_mode": "string",
  "hook_event_name": "string",
  "tool_name": "string (for tool events)",
  "tool_input": { "object (for tool events)" }
}
```

## JSON Output Format (stdout from command hooks)

```json
{
  "continue": true,
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow|deny|block",
    "permissionDecisionReason": "string"
  }
}
```

## Exit Code Meanings

| Code | Meaning | Behavior |
|------|---------|----------|
| 0 | Success | Continue execution |
| 2 | Blocking error | Prevent action, show error |
| Other | Non-blocking error | Log warning, continue |

## Best Practices

- [ ] Hooks are fast (< 5 seconds for sync hooks)
- [ ] Use `async: true` for long-running operations
- [ ] Use `once: true` for one-time setup hooks
- [ ] Use `statusMessage` for user visibility
- [ ] Quote all shell variables in scripts
- [ ] Use absolute paths or `$CLAUDE_PROJECT_DIR`
- [ ] Test hooks manually before deploying
