Skip to main content

Hooks Reference

Official technical reference for implementing hooks in Claude Code, covering all lifecycle events, input/output schemas, and security. Source: https://code.claude.com/docs/en/hooks.md Added: 2026-01-29


Hook Lifecycle Events

HookWhen It Fires
SessionStartSession begins or resumes
UserPromptSubmitUser submits a prompt
PreToolUseBefore tool execution
PermissionRequestWhen permission dialog appears
PostToolUseAfter tool succeeds
PostToolUseFailureAfter tool fails
SubagentStartWhen spawning a subagent
SubagentStopWhen subagent finishes
StopClaude finishes responding
PreCompactBefore context compaction
SessionEndSession terminates
NotificationClaude sends notifications

Configuration

Stored in settings files:

  • ~/.claude/settings.json (User)
  • .claude/settings.json (Project)
  • .claude/settings.local.json (Local, not committed)
  • Managed policy settings

Structure

{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here",
"timeout": 30
}
]
}
]
}
}

Matcher Rules

  • Exact match: Write
  • Regex: Edit|Write, Notebook.*
  • All tools: * or empty string

Hook Types

Command Hooks (type: "command")

Execute bash commands. Input via stdin (JSON), output via stdout/stderr.

Prompt Hooks (type: "prompt")

Send prompt to LLM (Haiku) for context-aware decisions.

{
"type": "prompt",
"prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete.",
"timeout": 30
}

Response schema: {"ok": true|false, "reason": "explanation"}

Best for Stop, SubagentStop, UserPromptSubmit, PreToolUse events.


Exit Codes

CodeBehavior
0Success. stdout shown in verbose mode. JSON parsed for structured control
2Blocking error. stderr fed back to Claude
OtherNon-blocking error. stderr shown in verbose mode

Exit Code 2 Behavior by Event

EventBehavior
PreToolUseBlocks tool call, shows stderr to Claude
PermissionRequestDenies permission, shows stderr to Claude
PostToolUseShows stderr to Claude (tool already ran)
UserPromptSubmitBlocks prompt, erases it, shows stderr to user
StopBlocks stoppage, shows stderr to Claude
SubagentStopBlocks stoppage, shows stderr to subagent
OthersShows stderr to user only

Common Hook Input Fields

{
"session_id": "abc123",
"transcript_path": "/path/to/session.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "..." },
"tool_use_id": "toolu_01ABC..."
}

Key Tool Input Schemas

Bash: { command, description, timeout, run_in_background } Write: { file_path, content } Edit: { file_path, old_string, new_string, replace_all } Read: { file_path, offset, limit }


JSON Output Control

Common Fields (all hooks)

{
"continue": true,
"stopReason": "string",
"suppressOutput": true,
"systemMessage": "string"
}

PreToolUse Decision Control

{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow|deny|ask",
"permissionDecisionReason": "reason",
"updatedInput": { "field": "new value" },
"additionalContext": "extra info for Claude"
}
}

PermissionRequest Decision Control

{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow|deny",
"updatedInput": { "command": "npm run lint" },
"message": "reason for deny",
"interrupt": false
}
}
}

PostToolUse Decision Control

{
"decision": "block",
"reason": "explanation"
}

Stop/SubagentStop Decision Control

{
"decision": "block",
"reason": "Must complete remaining tasks"
}

UserPromptSubmit

  • Plain text stdout: Added as context (exit code 0)
  • JSON with additionalContext: Structured context injection
  • "decision": "block": Prevents prompt processing

SessionStart

CLAUDE_ENV_FILE available for persisting environment variables:

echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"

Notification Matchers

  • permission_prompt - Permission requests
  • idle_prompt - Waiting for user input (60+ seconds)
  • auth_success - Authentication success
  • elicitation_dialog - MCP tool input needed

PreCompact Matchers

  • manual - From /compact
  • auto - From auto-compact

Setup Matchers

  • init - From --init or --init-only
  • maintenance - From --maintenance

SessionStart Matchers

  • startup - New session
  • resume - From --resume, --continue, /resume
  • clear - From /clear
  • compact - From compaction

Plugin Hooks

Defined in hooks/hooks.json at plugin root. Merged with user/project hooks. Uses ${CLAUDE_PLUGIN_ROOT} for plugin-relative paths.


Hooks in Skills and Agents

Supported events: PreToolUse, PostToolUse, Stop. Scoped to component lifecycle.

Skills support once: true to run hook only once per session.


Execution Details

  • Timeout: 60s default, configurable per command
  • Parallelization: All matching hooks run in parallel
  • Deduplication: Identical commands deduplicated
  • Environment: CLAUDE_PROJECT_DIR, CLAUDE_CODE_REMOTE
  • Safety: Snapshot at startup, warns if modified externally

Security Considerations

  1. Validate and sanitize inputs
  2. Always quote shell variables ("$VAR")
  3. Block path traversal (..)
  4. Use absolute paths
  5. Skip sensitive files (.env, .git/, keys)