# Set up Claude Code hooks for formatting, tests and protected files

> Add PostToolUse hooks that format and test after edits, a PreToolUse hook that blocks protected files, and a notification for long runs.

- **Category:** [Coding](https://stepgleam.com/categories/coding)
- **Difficulty:** Intermediate
- **Time:** ~30 minutes
- **Tools:** Claude Code, Git
- **Reliability score:** 82/100
- **Steps:** 6
- **Last updated:** 2026-10-26
- **Published:** 2026-10-26

## Tools used

- [Claude Code](https://code.claude.com/docs) — Runs the hooks at each lifecycle event
- [Git](https://git-scm.com) — Shares the project settings with the team

## What you'll get

A committed .claude/settings.json with hooks that run every time, whatever the model decides.

## Who this is for

Claude Code users who keep reminding it to format, test, or stay out of certain files.

## Before you start

Developers on r/ClaudeAI call hooks the feature most people skip. The setups they share are the same four: run tests after edits, format after edits, block certain files, and notify when a run finishes. Claude Code's docs give the exact config.

## Steps

### Step 1: Use hooks for anything that must always happen

Instructions in CLAUDE.md are advisory; hooks are deterministic. One user on blocking a folder: *"a hook that exits with an error when Claude tries to write there will stop it reliably. Much cleaner than hoping your instructions hold."*

[Open step 1](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-1)

### Step 2: Auto-format after every edit

**Tool:** Claude Code

In `.claude/settings.json`, add a `PostToolUse` hook with matcher `Edit|Write` that runs Prettier on the edited file; the docs' command is `jq -r '.tool_input.file_path' | xargs npx prettier --write`. One user's reason: *"Claude's style drifts in long sessions."*

[Open step 2](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-2)

### Step 3: Run tests after edits so Claude sees failures

**Tool:** Claude Code

Add a fast test command as another post-edit hook. *"Claude makes a change, tests run automatically, Claude sees the output and adjusts. It closes the feedback loop."*

[Open step 3](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-3)

### Step 4: Block protected files with a PreToolUse hook

**Tool:** Claude Code

Add a script in `.claude/hooks/` that reads the file path from stdin and exits with code **2** for patterns such as `.env`, `package-lock.json` or `.git/`, and register it as a `PreToolUse` hook on `Edit|Write`. Exit 2 blocks the action and sends your message back to Claude. *"Only pre tool use can actually stop Claude."*

**Why this works:** A blocked edit is explained to Claude so it can adjust.

[Open step 4](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-4)

### Step 5: Get notified when a long task finishes

**Tool:** Claude Code

Add a `Notification` hook (or one on `Stop`) that fires a desktop notification. One user includes the exit status *"so I know immediately if it finished clean or hit an error."*

[Open step 5](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-5)

### Step 6: Check with /hooks and commit the project settings

**Tool:** Claude Code

Run `/hooks` to confirm each hook is listed under the right event. `.claude/settings.json` can be committed so the team shares it; `.claude/settings.local.json` stays personal.

[Open step 6](https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files#step-6)

## Pro tips

- You can ask Claude to write the hook for you, e.g. "Write a hook that runs eslint after every file edit."
- Edit|Write hooks miss files changed through Bash; the docs suggest a Stop hook that scans the tree if that matters.

## Common mistakes

- Putting a must-always rule in CLAUDE.md instead of a hook.
- Running a slow full test suite on every edit.
- Using a catch-all matcher on a permission hook, which approves everything.

## FAQ

### Where do hooks live?

~/.claude/settings.json for every project, .claude/settings.json for one project.

### What does exit code 2 do?

It blocks the action and passes your stderr message to Claude.

---

Canonical guide: https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files
Read this guide as Markdown: https://stepgleam.com/guides/set-up-claude-code-hooks-for-formatting-tests-and-protected-files.md
