---
title: "Claude Code Hooks: Automate Your Quality Gates"
description: "Learn what Claude Code hooks are, every lifecycle event, and how to set them up in settings.json to run lint, tests and format automatically and block bad actions."
type: "guide"
locale: "en"
category: "Claude Code"
canonical: "https://agenticschool.dev/guides/claude-code-hooks"
datePublished: "2026-06-13"
dateModified: "2026-06-13"
---

# Claude Code Hooks: Automate Your Quality Gates

- Category: Claude Code
- Keywords: claude code hooks, claude code hooks tutorial, pretooluse posttooluse, automate claude code, claude code quality gates
- Canonical URL: https://agenticschool.dev/guides/claude-code-hooks
- Locale: en

> Learn what Claude Code hooks are, every lifecycle event, and how to set them up in settings.json to run lint, tests and format automatically and block bad actions.

Claude Code hooks are shell commands that Claude Code runs automatically at specific points in its lifecycle, so you can enforce your quality gates deterministically instead of hoping the agent remembers. Where a CLAUDE.md rule is a suggestion the model may or may not follow, a hook always fires: it can run your formatter after every file write, run your tests before the agent stops, or block a dangerous command outright. This guide explains the hook events, how hooks are configured, and a practical setup you can copy today.

## What a hook actually is

Every hook has three parts: an event (the lifecycle moment it fires on), an optional matcher (a filter so it only runs for certain tools), and an action (the shell command it runs). When a hook fires, Claude Code passes it JSON on standard input describing the event (session id, working directory, the tool name and its input), and your script decides what to do. The command exit code controls flow: exit 0 means proceed, and a non-zero exit (conventionally 2) blocks the action and feeds your message back to the agent so it can react.

- Event: when the hook fires (for example after a tool runs).
- Matcher: an optional filter, for example only on file edits.
- Action: the shell command Claude Code executes.

## The lifecycle events you can hook

Hooks cover the full tool lifecycle. The ones you will use most are PreToolUse and PostToolUse (around every tool call), Stop (when the agent is about to finish), and SessionStart (when a session begins). There are more for finer control.

- PreToolUse: before a tool runs - validate or block the action.
- PostToolUse: after a tool runs - format, lint or check the result.
- UserPromptSubmit: when you send a prompt - inject context or guard input.
- Stop and SubagentStop: when the agent (or a subagent) is about to stop - run tests as a final gate.
- SessionStart and Notification: session setup and when the agent needs your attention.

## Where hooks are configured

Hooks live in your Claude Code settings.json. Put team-wide, non-negotiable gates in the project file at .claude/settings.json so everyone shares the same guardrails, and keep personal preferences in your user settings. Each entry pairs an event with a matcher and the command to run.

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "bun run lint --fix" }
        ]
      }
    ]
  }
}
```
A PostToolUse hook that runs your linter after every file edit or write.

## A practical quality-gate setup

The highest-leverage setup is small: format and lint on every write, and run your test suite as a Stop gate so the agent cannot declare a task done with red tests. Add a PreToolUse guard if you want to block destructive shell commands. Keep hook scripts fast and idempotent, because they run often, and write to standard error with a clear message when you block so the agent knows how to fix it.

## Steps

### 1. Create your settings file

Create .claude/settings.json in your project root if it does not exist. This is where shared, team-wide hooks live.

### 2. Add a PostToolUse format and lint hook

Under hooks.PostToolUse, add a matcher of "Edit|Write" and a command that runs your formatter and linter, so code is tidied after every change the agent makes.

### 3. Add a Stop hook that runs your tests

Under hooks.Stop, add a command that runs your test suite. Exit non-zero on failure so the agent cannot finish with failing tests and instead keeps fixing them.

### 4. Add a PreToolUse guard for risky commands

Under hooks.PreToolUse with a Bash matcher, add a script that inspects the command from stdin JSON and exits 2 to block destructive operations such as force-push or recursive delete.

### 5. Test and commit

Make a small edit and confirm the hooks fire as expected, then commit the settings file so the whole team inherits the same guardrails.

## FAQ

### What are Claude Code hooks?

Hooks are shell commands Claude Code runs automatically at points in its lifecycle, such as before or after a tool call or when the agent is about to stop. They let you enforce quality gates deterministically, like running tests or a formatter, instead of relying on the model to remember.

### Where do I configure Claude Code hooks?

In your Claude Code settings.json. Put shared, team-wide hooks in the project file at .claude/settings.json and keep personal ones in your user settings. Each hook pairs an event with an optional matcher and the command to run.

### Can a hook block an action?

Yes. A PreToolUse hook that exits with a non-zero code (conventionally 2) blocks the tool call, and the message you print is fed back to the agent so it can adjust. This is how you stop destructive commands before they run.

### What is the difference between a hook and a CLAUDE.md rule?

A CLAUDE.md rule is guidance the model may or may not follow. A hook is deterministic: it always runs the command you configured at the chosen event, so it is the right tool for non-negotiable gates like tests, formatting and safety checks.
