Runs your formatter on each file Claude edits, so diffs stay clean and style never needs a review comment.
WHEN TO USE IT
When you are tired of reformatting Claude's output, or of formatting noise in every pull request.
Formats change. If a field stops working, check it against Anthropic's documentation.
Read it before you install it. A hook runs with your user account's permissions, on its own, every time it is triggered. That is what makes it useful, and why a stranger's should never be installed unread — this one included.
PostToolUse runs after the edit has landed. It cannot undo it — it can only react — which is exactly right for formatting.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format.sh"
}
]
}
]
}
}
Picks a formatter by extension and skips anything not installed. Exit 0 even on failure: a formatter error should not interrupt the session.
#!/usr/bin/env bash
# Formats the file that was just edited.
file=$(jq -r '.tool_input.file_path // empty')
[ -f "$file" ] || exit 0
have() { command -v "$1" >/dev/null 2>&1; }
case "$file" in
*.js|*.jsx|*.ts|*.tsx|*.css|*.json|*.md)
have npx && npx --no-install prettier --write "$file" >/dev/null 2>&1 ;;
*.py)
have ruff && ruff format "$file" >/dev/null 2>&1 ;;
*.go)
have gofmt && gofmt -w "$file" ;;
*.cs)
have dotnet && dotnet format whitespace --include "$file" >/dev/null 2>&1 ;;
esac
exit 0
Commit both files and everyone on the project gets the same formatting.
mkdir -p .claude/hooks
mv format.sh .claude/hooks/
chmod +x .claude/hooks/format.sh
MORE HOOKS
The authority
Anthropic's documentation for Hooks
This template is a starting point. Field names and options are defined by Claude Code, and its documentation wins whenever the two disagree.
https://code.claude.com/docs/en/hooks