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
--bareis the recommended mode for scripts (needsANTHROPIC_API_KEY; no OAuth/keychain). Without it,-pstill runs the repo's hooks and.mcp.jsonservers, even in an untrusted folder.- Since v2.1.302
-pstarts in Manual mode if nothing sets a mode: calls that need approval are denied unless allowed by--allowedTools/permissions.allow, aPermissionRequesthook or--permission-mode.--permission-prompts none(v2.1.259+) denies without waiting on a host. --allowedTools/--disallowedToolsas in Claude Permissions. The-pCLI is the Agent SDK's CLI form.- Built-in terminal-only commands (
/login…) don't run;/model,/effort,/fast,/rename,/output-style x,/config key=valuetake arguments. - Exit code 0 on success, non-zero on failure, 143 after SIGTERM.
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
- Recurring tasks expire after 7 days (they fire once more, then delete). Up to 50 tasks per session. Runs fire between your turns; recurring ones get jitter (up to half the gap, max 30 min;
*/5is exempt). - One-off reminders: plain language ("remind me at 3pm…"), not
/loop. - Stop:
Escfor a self-paced loop; for fixed-interval loops ask Claude to cancel ("cancel the deploy check job"). Tools: CronCreate / CronList / CronDelete / ScheduleWakeup. - Restored on
--resume/--continue(except expired, passed one-shots and self-paced loops).CLAUDE_CODE_DISABLE_CRON=1turns it all off. Prefer cloud tasks or GitHub Actions for unattended work; considerMonitorinstead of polling.
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).
- Setup:
/install-github-app(github.com repos only, needsghand repo admin) installs the app, saves the secret, opens a workflow PR. Manual: install the Claude GitHub App, add a secret, copyexamples/claude.yml. - Secrets:
ANTHROPIC_API_KEY(Console key) orCLAUDE_CODE_OAUTH_TOKEN(subscription; generate withclaude setup-token). Org-wide: use an API key or workload identity federation (anthropic_federation_rule_id…). - Modes: no
promptinput = interactive (reacts to@claude); withprompt= automation (any event, e.g. cron). Triggering user needs write access; bots must be inallowed_bots. - Inputs:
prompt(text or/skill),claude_args(CLI flags like--max-turns,--model,--allowedTools),plugins+plugin_marketplaces,settings,trigger_phrase,use_bedrock/use_vertex/use_foundry.
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 }}" }
- Migrating from
@beta:direct_prompt→prompt, dropmode, movemax_turns/modelintoclaude_args. - GitLab has its own CI/CD integration.
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