Hooks
Hooks let you run custom shell commands automatically in response to Claude Code tool events. They are the mechanism for injecting your own automation into Claude Code's workflow — running formatters on file writes, logging tool calls, or running tests after edits.
What Hooks Are and When They Fire
A hook is a shell command that Claude Code executes automatically when a specific event occurs. The two main hook types:
- PreToolUse: Fires before Claude Code runs a tool. Can be used to validate, log, or block the tool call. If the hook exits with a non-zero code, the tool call is blocked.
- PostToolUse: Fires after a tool completes. Used for side effects like auto-formatting, running tests, or logging results. Exit code is informational — it does not block the workflow.
Hooks can be scoped to specific tool names: Bash, Edit, Write, Read, Glob, Grep, and MCP tool names.
Configuring Hooks in settings.json
Hooks are defined in ~/.claude/settings.json (global) or .claude/settings.json in your project directory (project-scoped):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "prettier --write "$CLAUDE_TOOL_INPUT_FILE_PATH""
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo "[HOOK] Bash command: $CLAUDE_TOOL_INPUT_COMMAND" >> /tmp/claude-audit.log"
}
]
}
]
}
}The matcher field is a regex matched against the tool name. Hook commands receive context via environment variables set by Claude Code.
Hook Environment Variables
Claude Code sets these environment variables for hooks:
CLAUDE_TOOL_NAME— the name of the tool being called (e.g.,Edit)CLAUDE_TOOL_INPUT_FILE_PATH— for file tools: the path being read/writtenCLAUDE_TOOL_INPUT_COMMAND— for Bash tool: the command being runCLAUDE_TOOL_OUTPUT— for PostToolUse: the tool's output (PostToolUse only)
Common Use Cases
Auto-format on write
PostToolUse on Edit/Write → run prettier --write or black on the modified file. Ensures all Claude-generated code matches your project's formatting standards without manual formatting steps.
Run tests after edit
PostToolUse on Edit → run the test file corresponding to the edited source file. Gives Claude immediate feedback on whether its changes break tests, enabling automatic fix-retry loops.
Audit log of shell commands
PreToolUse on Bash → append the command to an audit log file. Provides a record of every shell command Claude Code ran in a session — useful for security review and debugging.
Block dangerous commands
PreToolUse on Bash → check if the command matches a blocklist (e.g., rm -rf, DROP TABLE) and exit non-zero to block it. A last-resort safety net for agentic sessions with broad permissions.
Security Considerations
Hooks run as shell commands with the same permissions as your Claude Code process. This means:
- Hooks can read and write files, make network requests, and execute arbitrary code
- A malicious MCP server could theoretically influence hook execution via tool names or outputs — keep hooks simple and explicit
- Be careful with hooks that pass
$CLAUDE_TOOL_INPUT_COMMANDdirectly to a shell — this creates a command injection risk. Quote variables carefully or avoid passing them to shell interpreters. - Test hooks thoroughly before enabling them in agentic sessions — a misconfigured PreToolUse hook that always exits non-zero will block all matching tool calls
Checklist: Do You Understand This?
- PreToolUse runs before a tool; PostToolUse runs after — PreToolUse can block the call by exiting non-zero
- Configure in settings.json with a
matcher(tool name regex) and a shellcommand - Hook commands receive tool context via environment variables (
CLAUDE_TOOL_NAME,CLAUDE_TOOL_INPUT_FILE_PATH, etc.) - Common uses: auto-format on write, run tests after edit, audit log, block dangerous patterns
- Hooks have full shell access — keep them simple, test thoroughly, and quote variables to prevent injection