Hooks and permissions
Customize Claude's behavior and set safety guardrails
⏱ Est. ~6 min
01 · Read
Hooks let you run your own code at specific moments in Claude's workflow. Before a tool runs? After an edit? When a session starts? You can intercept these events to add your own logic — auto-formatting, security checks, notifications, custom validation.
Permissions control what Claude is allowed to do. By default Claude asks before running commands or editing files. But you can pre-approve safe actions (like npm test) and block dangerous ones (like git push --force), so Claude moves faster on routine tasks and stays safe on risky ones.
💡 Picture thisHooks are like checkpoints on a production line. At each station, an inspector (your script) checks the work, waves it through (exit 0) or sends it back (exit 2). Permissions are like a security badge system — some doors are always open (reading files), some require a badge (commands), some are locked (dangerous operations).
Key points
- Hooks: run your code at specific moments in Claude's workflow
- Permissions: control what Claude can and cannot do
- Hooks intercept events; permissions set blanket rules
- Together they customize and protect Claude for your workflow
02 · Read
Here are the most useful hook events:- PreToolUse — Fires before Claude uses a tool (Read, Edit, Bash, etc). You can inspect what it's about to do and block it. - PostToolUse — Fires after a tool succeeds. Great for auto-formatting edited files or logging changes. - SessionStart — Fires when a session begins. Use this to inject context reminders, especially after compaction. - Notification — Fires when Claude needs your attention. Great for desktop notifications. - Stop — Fires when Claude finishes responding.
Hooks communicate via exit codes: exit 0 means allow the action, exit 2 means block it (and your error message on stderr becomes feedback to Claude).
Key points
- PreToolUse: inspect and optionally block before tools run
- PostToolUse: react after tools succeed (auto-format, log)
- SessionStart: inject context at session start or after compaction
- Exit 0 = allow, Exit 2 = block (stderr becomes feedback)
03 · Code example
Below is a PostToolUse hook that auto-formats files after Claude edits them. Lives in your project's .claude/settings.json.
.claude/settings.json — auto-format hook
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}]
}]
}
}
The matcher field uses a regex to match tool names — Edit|Write means this hook fires after any Edit or Write tool call. The command receives JSON on stdin with tool call details, extracts the file path, and runs Prettier against it. Every file Claude edits gets formatted automatically.
04 · Code example
Below is a PreToolUse hook that blocks dangerous Bash commands.
.claude/hooks/protect.sh
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
if [[ "$CMD" =~ "rm -rf" ]]; then
echo "Blocked: rm -rf is not allowed" >&2
exit 2 # Block the action
fi
exit 0 # Allow everything else
.claude/settings.json
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": ".claude/hooks/protect.sh"
}]
}]
}
}
This hook intercepts every Bash command Claude tries to run. It reads the command from stdin (as JSON), checks for 'rm -rf', and blocks it with exit code 2. The error message on stderr tells Claude why it was blocked, and Claude accepts the restriction.
05 · Read
Permissions give you blanket allow/deny rules without writing scripts. They match flexibly using wildcards.
Allow rules pre-approve actions so Claude doesn't have to ask:- Bash(npm run ) — any npm script - Bash(git commit ) — commit changes - Read(*.env) — read env files
Deny rules block actions outright:- Bash(git push --force ) — no force pushes - Edit(package-lock.json) — don't touch the lockfile - Bash(rm -rf ) — no recursive deletes
Deny rules always beat allow rules. Settings are checked from most specific to least specific: local project > project > user.
Key points
- Allow rules: pre-approve safe actions (no permission prompts)
- Deny rules: block actions outright
- Wildcards: Bash(npm *) matches any npm command
- Deny always beats allow on conflict
- Local settings override project override user
06 · Quiz
Your PreToolUse hook detects that Claude is about to run rm -rf /tmp/build. What exit code should your hook script return to block the action?
- Exit code 0 — success
- Exit code 2 — block the action
- Exit code 1 — generic error
- Exit code 255 — fatal error
07 · Match
Match each hook event to what it's best for.
(This section is interactive — please enable JavaScript.)
Other lessons in this chapter
⚠ The full interactive experience needs JavaScript. Please enable it and reload.
※ This is an independent Traditional Chinese teaching project — not an official Anthropic product. Claude™ is a trademark of Anthropic, PBC.