Claude Hooks and Automation

Hooks

User-defined handlers run at lifecycle points, configured under hooks in settings.

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
    }]
  }
}

Hook types: command (stdin JSON), http (POST), mcp_tool, prompt (single-turn LLM decision), agent (subagent verifier, experimental). SessionStart supports only command and mcp_tool.

Events (33):

Group Events
Session Setup, SessionStart, SessionEnd
Prompt UserPromptSubmit, UserPromptExpansion
Tool PreToolUse, PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure, PostToolBatch
Agents/tasks SubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle
Turn Notification, MessageDisplay, Stop, StopFailure
Context/config InstructionsLoaded, ConfigChange, CwdChanged, DirectoryAdded, FileChanged, PreCompact, PostCompact
Worktree WorktreeCreate, WorktreeRemove
Model/MCP PreModelSwitch, PostModelSwitch, Elicitation, ElicitationResult

Matchers: omitted/""/"*" = all; only letters, digits, _ - , | and spaces = exact list (Edit|Write); anything else = unanchored JS regex (mcp__memory__.*). Events without matcher support ignore the field. Matcher targets: tool name, notification type, agent type, startup|resume|clear|compact|fork (SessionStart), manual|auto (compact), MCP server name…

Config shape: event → array of matcher groups → hooks array of handlers (type, command, timeout…). Use ${CLAUDE_PROJECT_DIR} in commands.
Exit codes: 0 success (stdout parsed as JSON; on SessionStart/UserPromptSubmit plain text goes to Claude's context) · 2 blocking error (stderr shown, action blocked: denies PreToolUse, blocks a prompt, deletes a TaskCreated task) · other = non-blocking error.
JSON output: continue, stopReason, systemMessage, decision: "block" + reason, and hookSpecificOutput with hookEventName plus e.g. additionalContext, permissionDecision (allow|deny|ask|defer), updatedInput, updatedToolOutput, sessionTitle.
Env vars: CLAUDE_PROJECT_DIR, CLAUDE_ENV_FILE (append export X=y in SessionStart/Setup/CwdChanged/FileChanged to persist into Bash), CLAUDE_PLUGIN_DATA.

Debug: /hooks (registered?), --debug then read the log.
Controls: disableAllHooks, allowedHttpHookUrls, httpHookAllowedEnvVars, allowManagedHooksOnly (see Claude Settings).
Hooks enforce; CLAUDE.md only advises, so block actions with a PreToolUse hook.

Notifications

Fires when Claude is done or needs you. Kitty/Ghostty notify natively; iTerm2 needs config; Windows/WSL2 need a hook. Use matcher on the Notification event:

notification_type Meaning
permission_prompt Needs tool-use approval
idle_prompt Finished ~60s ago and you haven't typed
auth_success Authentication completed
elicitation_dialog / elicitation_url_dialog / elicitation_complete / elicitation_response MCP elicitation stages
agent_needs_input / agent_completed Background session waiting / finished or failed
quota_auto_resume_fired / _stale / _disabled Resume after a usage-limit reset
plugin_notification A plugin raised one
{ "hooks": { "Notification": [{ "matcher": "idle_prompt",
  "hooks": [{ "type": "command", "command": "New-BurntToastNotification -Text 'Claude Code','Task complete'" }] }] } }

Payload fields: session_id, transcript_path, cwd, permission_mode, hook_event_name, message, title, notification_type.

Headless (-p)

claude -p "refactor auth to OAuth2"
claude -p --permission-mode plan "create a migration plan"
claude -p --max-turns 10 "run tests and fix failures"       # print mode only
claude -p "generate API docs" > docs/api.md
cat error.log | claude -p "diagnose this error"              # stdin capped at 10MB
claude -p "summarize" --output-format json | jq -r .result   # text | json | stream-json
claude -p "extract names" --output-format json --json-schema '{...}'   # → .structured_output
claude --bare -p "Summarize README.md" --allowedTools "Read" # CI: skips hooks, plugins, MCP, memory, CLAUDE.md

Agent SDK

Same engine from CLI, Python, or TypeScript (CLI mode was "headless").

from claude_agent_sdk import query, ClaudeAgentOptions
async for msg in query(
    prompt="Find and fix the bug in auth.py",
    options=ClaudeAgentOptions(allowed_tools=["Read", "Edit", "Bash"], permission_mode="acceptEdits"),
):
    print(msg)

Messages stream as AssistantMessage (text / tool blocks) and a final ResultMessage.

Scheduling

Cloud Desktop /loop (session)
Runs on Anthropic cloud Your machine Your machine, session open
Needs machine/session No Machine on Session open
Min interval 1 hour 1 min (Claude-set) / 1 h (forms) 1 minute
/loop 5m check if the deployment finished      # fixed interval (s/m/h/d; rounded to cron steps)
/loop check CI and address review comments     # no interval: Claude picks 1 min–1 h each iteration
/loop                                          # built-in maintenance prompt, or .claude/loop.md / ~/.claude/loop.md
/loop 20m /review-pr 1234                      # skills allowed to self-invoke only

GitHub Actions

anthropics/claude-code-action@v1 runs Claude Code in workflows: mention @claude in an issue/PR to analyze, implement and push. Runs on GitHub runners (uses your Actions minutes plus API tokens or your subscription).

on:
  issue_comment: { types: [created] }
  pull_request_review_comment: { types: [created] }
jobs:
  claude:
    if: contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    permissions: { contents: write, pull-requests: write, issues: write, id-token: write, actions: read }
    steps:
      - uses: actions/checkout@v6
        with: { fetch-depth: 1 }
      - uses: anthropics/claude-code-action@v1
        with: { anthropic_api_key: "${{ secrets.ANTHROPIC_API_KEY }}" }

Reviews

Feature How
/security-review Terminal scan of pending changes for injection, XSS, authn/authz flaws, insecure data handling
/code-review (alias /review) Bundled skill; review your branch/PR locally on any plan
Code Review (service) Team and Enterprise, GitHub only. Agents find → verify → rank, then post inline comments, a summary and a "Claude Code Review" check run (never approves/blocks). Trigger per repo (on open / every push / on request) or comment @claude review
Ultrareview /code-review ultra: cloud multi-agent review, user-triggered and billed

Code Review levels: Quick, Standard (default), Deep. Tune what it flags with REVIEW.md (read from the base/default branch only) and CLAUDE.md. Billed via usage credits with a monthly spend limit. Not available with Zero Data Retention, HIPAA config or CMEK.
Severity tags: Normal, Nit, Pre-existing.


Related: Claude Permissions, Claude Settings, Claude Subagents and Teams