Configure Claude Code hooks to automate your workflow

Configure Claude Code hooks to automate your workflow

Dec 11, 2025

A modern office space with large windows showcases professionals engaged in discussions around a wooden table, surrounded by greenery and urban skyline views.
A modern office space with large windows showcases professionals engaged in discussions around a wooden table, surrounded by greenery and urban skyline views.

Claude Code hooks are deterministic triggers that run your shell commands at specific points in Claude Code’s lifecycle. Use them to auto-format files after edits, enforce project rules, block risky ops, inject context at session start, or notify you when input’s needed—without relying on the model to “remember”.

Why hooks matter

Prompts are great for suggestions; hooks are guarantees. They fire every time the matching event occurs (e.g., before a tool runs, after an edit, when a session starts/ends). That means consistent formatting, policy enforcement and guardrails across your team—no extra prompting required.

What Claude Code hooks can do

  • Pre-empt risky actions: Block writes to .env, production config, or /.git. (Use PreToolUse with exit-code control.)

  • Auto-apply standards: Run prettier, gofmt, or your linter after every edit/write (PostToolUse).

  • Inject context automatically: At SessionStart, load recent tickets or a coding checklist into the conversation.

  • Clickless notifications: Desktop pop-ups when Claude needs approval (Notification).

  • Gate prompts/tools: Approve, deny, or ask for confirmation via PreToolUse / PermissionRequest decision control.

Hooks are configured in user, project, or local project settings—and can also be enforced via enterprise policy settings. Claude Code

The hook events you’ll actually use

  • PreToolUse / PermissionRequest / PostToolUse — wrap tool calls (Bash, Edit, Write, Read, Grep, WebFetch, Task/subagents). Allow, deny or ask; modify inputs; or give feedback after.

  • UserPromptSubmit — validate or enrich prompts before Claude processes them; you can inject text or structured context.

  • SessionStart / SessionEnd — set up environment, load context, and clean up/log at the end.

  • Notification, Stop, SubagentStop, PreCompact — alerts, end-of-response control, and compaction hooks.

A fast, safe setup (5 steps)

  1. Open the Hooks UI: run /hooks inside Claude Code. Choose an event (e.g., PreToolUse).

  2. Add a matcher: e.g., Edit|Write to intercept file changes, or Bash to govern shell commands. * matches everything.

  3. Add the hook: choose type: "command" and enter your shell command (it receives JSON on stdin; use jq/Python to parse).

  4. Choose storage:

    • ~/.claude/settings.json (user),

    • .claude/settings.json (project, commit to repo),

    • .claude/settings.local.json (local only),

    • or enterprise policy (centrally enforced).

  5. Verify & test: /hooks shows your config; run a quick command and check your log/output.

Copy-ready examples

1) Log every Bash command (quick audit)

Register under PreToolUse with matcher Bash:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

This runs before each Bash tool call and appends a line to a log file. Claude Code

2) Auto-format TypeScript after edits/writes

PostToolUse with matcher Edit|Write:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Claude Code

3) Protect sensitive files (block with exit code 2)

PreToolUse with matcher Edit|Write:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; d=json.load(sys.stdin); p=d.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(x in p for x in ['.env','package-lock.json','.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

Exit code 2 blocks the action and surfaces your stderr to Claude (and/or the user) according to the per-event rules. Claude Code

4) Get desktop alerts when Claude needs you

Notification hook:

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          { "type": "command", "command": "notify-send 'Claude Code' 'Awaiting your input'" }
        ]
      }
    ]
  }
}

Claude Code

5) Pre-load context at session start

SessionStart can inject extra guidance or a checklist:

  • Write plain text to stdout (exit code 0) to add context, or

  • Return JSON with hookSpecificOutput.additionalContext.

Advanced control: exit codes & JSON decisions

  • 0: success. stdout may be parsed as JSON for structured control (e.g., "allow"|"deny"|"ask" on PreToolUse; "block" on PostToolUse/Stop; add additionalContext).

  • 2: blocking error. Skips JSON; uses stderr as the message and blocks per-event rules (e.g., deny a PreToolUse).

  • Other non-zero: non-blocking; shows stderr in verbose mode.

CI and non-interactive use (bonus)

Combine hooks with headless mode to run Claude Code in CI, build scripts or pre-commit style jobs: claude -p "<prompt>" --output-format stream-json. Headless mode is per session, so trigger it each run. Anthropic

Security & governance essentials

  • Hooks run automatically with your user’s credentials; review scripts carefully and follow the Security Best Practices (quote variables, validate inputs, avoid sensitive paths, use absolute paths).

  • Config edits don’t hot-apply: Claude snapshots hooks at session start and asks you to review changes in /hooks—a protection against malicious modifications.

  • Enterprise can enforce policy hooks org-wide for consistency.

FAQs

What are Claude Code hooks?
User-defined shell commands that run at specific lifecycle events in Claude Code (e.g., PreToolUse, PostToolUse, SessionStart) to enforce rules, automate tasks, or add context. Claude Code

Where do I configure them?
In ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json, or via enterprise policy settings; /hooks offers an interactive editor. Claude Code

How do I block dangerous actions?
Return exit code 2 from a PreToolUse/PermissionRequest hook to deny the action and send your error message back to Claude; or use JSON decision control to “deny/ask/allow”. Claude Code

Can I add context automatically?
Yes—UserPromptSubmit and SessionStart can inject text or structured additionalContext into the conversation before Claude proceeds. Claude Code

Do hooks work with plugins/MCP tools?
Yes—plugins can contribute hooks, and you can target MCP tools via matchers; multiple hooks can run in parallel for a single event. Claude Code

Claude Code hooks are deterministic triggers that run your shell commands at specific points in Claude Code’s lifecycle. Use them to auto-format files after edits, enforce project rules, block risky ops, inject context at session start, or notify you when input’s needed—without relying on the model to “remember”.

Why hooks matter

Prompts are great for suggestions; hooks are guarantees. They fire every time the matching event occurs (e.g., before a tool runs, after an edit, when a session starts/ends). That means consistent formatting, policy enforcement and guardrails across your team—no extra prompting required.

What Claude Code hooks can do

  • Pre-empt risky actions: Block writes to .env, production config, or /.git. (Use PreToolUse with exit-code control.)

  • Auto-apply standards: Run prettier, gofmt, or your linter after every edit/write (PostToolUse).

  • Inject context automatically: At SessionStart, load recent tickets or a coding checklist into the conversation.

  • Clickless notifications: Desktop pop-ups when Claude needs approval (Notification).

  • Gate prompts/tools: Approve, deny, or ask for confirmation via PreToolUse / PermissionRequest decision control.

Hooks are configured in user, project, or local project settings—and can also be enforced via enterprise policy settings. Claude Code

The hook events you’ll actually use

  • PreToolUse / PermissionRequest / PostToolUse — wrap tool calls (Bash, Edit, Write, Read, Grep, WebFetch, Task/subagents). Allow, deny or ask; modify inputs; or give feedback after.

  • UserPromptSubmit — validate or enrich prompts before Claude processes them; you can inject text or structured context.

  • SessionStart / SessionEnd — set up environment, load context, and clean up/log at the end.

  • Notification, Stop, SubagentStop, PreCompact — alerts, end-of-response control, and compaction hooks.

A fast, safe setup (5 steps)

  1. Open the Hooks UI: run /hooks inside Claude Code. Choose an event (e.g., PreToolUse).

  2. Add a matcher: e.g., Edit|Write to intercept file changes, or Bash to govern shell commands. * matches everything.

  3. Add the hook: choose type: "command" and enter your shell command (it receives JSON on stdin; use jq/Python to parse).

  4. Choose storage:

    • ~/.claude/settings.json (user),

    • .claude/settings.json (project, commit to repo),

    • .claude/settings.local.json (local only),

    • or enterprise policy (centrally enforced).

  5. Verify & test: /hooks shows your config; run a quick command and check your log/output.

Copy-ready examples

1) Log every Bash command (quick audit)

Register under PreToolUse with matcher Bash:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

This runs before each Bash tool call and appends a line to a log file. Claude Code

2) Auto-format TypeScript after edits/writes

PostToolUse with matcher Edit|Write:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Claude Code

3) Protect sensitive files (block with exit code 2)

PreToolUse with matcher Edit|Write:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; d=json.load(sys.stdin); p=d.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(x in p for x in ['.env','package-lock.json','.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

Exit code 2 blocks the action and surfaces your stderr to Claude (and/or the user) according to the per-event rules. Claude Code

4) Get desktop alerts when Claude needs you

Notification hook:

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          { "type": "command", "command": "notify-send 'Claude Code' 'Awaiting your input'" }
        ]
      }
    ]
  }
}

Claude Code

5) Pre-load context at session start

SessionStart can inject extra guidance or a checklist:

  • Write plain text to stdout (exit code 0) to add context, or

  • Return JSON with hookSpecificOutput.additionalContext.

Advanced control: exit codes & JSON decisions

  • 0: success. stdout may be parsed as JSON for structured control (e.g., "allow"|"deny"|"ask" on PreToolUse; "block" on PostToolUse/Stop; add additionalContext).

  • 2: blocking error. Skips JSON; uses stderr as the message and blocks per-event rules (e.g., deny a PreToolUse).

  • Other non-zero: non-blocking; shows stderr in verbose mode.

CI and non-interactive use (bonus)

Combine hooks with headless mode to run Claude Code in CI, build scripts or pre-commit style jobs: claude -p "<prompt>" --output-format stream-json. Headless mode is per session, so trigger it each run. Anthropic

Security & governance essentials

  • Hooks run automatically with your user’s credentials; review scripts carefully and follow the Security Best Practices (quote variables, validate inputs, avoid sensitive paths, use absolute paths).

  • Config edits don’t hot-apply: Claude snapshots hooks at session start and asks you to review changes in /hooks—a protection against malicious modifications.

  • Enterprise can enforce policy hooks org-wide for consistency.

FAQs

What are Claude Code hooks?
User-defined shell commands that run at specific lifecycle events in Claude Code (e.g., PreToolUse, PostToolUse, SessionStart) to enforce rules, automate tasks, or add context. Claude Code

Where do I configure them?
In ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json, or via enterprise policy settings; /hooks offers an interactive editor. Claude Code

How do I block dangerous actions?
Return exit code 2 from a PreToolUse/PermissionRequest hook to deny the action and send your error message back to Claude; or use JSON decision control to “deny/ask/allow”. Claude Code

Can I add context automatically?
Yes—UserPromptSubmit and SessionStart can inject text or structured additionalContext into the conversation before Claude proceeds. Claude Code

Do hooks work with plugins/MCP tools?
Yes—plugins can contribute hooks, and you can target MCP tools via matchers; multiple hooks can run in parallel for a single event. Claude Code

Get practical advice delivered to your inbox

By subscribing you consent to Generation Digital storing and processing your details in line with our privacy policy. You can read the full policy at gend.co/privacy.

Ready to get the support your organisation needs to successfully use AI?

Miro Solutions Partner
Asana Platinum Solutions Partner
Notion Platinum Solutions Partner
Glean Certified Partner

Ready to get the support your organisation needs to successfully use AI?

Miro Solutions Partner
Asana Platinum Solutions Partner
Notion Platinum Solutions Partner
Glean Certified Partner

Generation
Digital

UK Office
33 Queen St,
London
EC4R 1AP
United Kingdom

Canada Office
1 University Ave,
Toronto,
ON M5J 1T1,
Canada

NAMER Office
77 Sands St,
Brooklyn,
NY 11201,
United States

EMEA Office
Charlemont St, Saint Kevin's, Dublin,
D02 VN88,
Ireland

Middle East Office
6994 Alsharq 3890,
An Narjis,
Riyadh 13343,
Saudi Arabia

UK Fast Growth Index UBS Logo
Financial Times FT 1000 Logo
Febe Growth 100 Logo

Company No: 256 9431 77 | Copyright 2026 | Terms and Conditions | Privacy Policy

Generation
Digital

UK Office
33 Queen St,
London
EC4R 1AP
United Kingdom

Canada Office
1 University Ave,
Toronto,
ON M5J 1T1,
Canada

NAMER Office
77 Sands St,
Brooklyn,
NY 11201,
United States

EMEA Office
Charlemont St, Saint Kevin's, Dublin,
D02 VN88,
Ireland

Middle East Office
6994 Alsharq 3890,
An Narjis,
Riyadh 13343,
Saudi Arabia

UK Fast Growth Index UBS Logo
Financial Times FT 1000 Logo
Febe Growth 100 Logo


Company No: 256 9431 77
Terms and Conditions
Privacy Policy
Copyright 2026