Blog · August 2, 2026 · 7 min read · by Vilva Athiban P B

Claude Code Hooks: A Practical Guide to Automating Your Agent Workflow

Everything you put in a prompt or a CLAUDE.md file is, in the end, a suggestion. Claude Code usually follows it — but "usually" is not a guarantee, and for some things you want a guarantee. Always run the formatter after edits. Never touch the production config. Tell me the moment you finish.

That's what hooks are for. A Claude Code hook is a shell command that runs automatically at a specific point in the agent's lifecycle — before a tool call, after a file edit, when the session ends, when Claude stops and waits for you. It's deterministic: the hook fires every single time the event happens, whether or not the model "remembers" to do it. Here's how to set them up, engineer to engineer, with the three hooks that pay off immediately.

Where hooks live

Hooks are plain JSON in your settings files. Three locations matter:

  • ~/.claude/settings.json — applies to every project on your machine.
  • .claude/settings.json — lives in the repo, so the whole team gets the hook when they pull.
  • .claude/settings.local.json — project-specific but gitignored, for personal stuff you don't want to commit.

The structure has three levels: the event (when it fires), an optional matcher (which tool triggers it), and one or more handlers (what runs). A minimal example:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "npx prettier --write ." }
        ]
      }
    ]
  }
}

That's a complete, working hook: every time Claude edits or writes a file, Prettier runs. No prompt engineering, no hoping the model remembers your style guide. Matchers accept exact tool names, pipe-separated lists like Edit|Write, or regex; leave the matcher out (or use *) to fire on everything.

Hook #1: auto-format after every edit

The example above is the classic first hook, and it's worth setting up today. PostToolUse fires after a tool call succeeds, and your hook receives a JSON payload on stdin describing exactly what happened — including tool_input.file_path, so you can format only the file that changed instead of the whole repo:

#!/bin/bash
FILE=$(jq -r '.tool_input.file_path')
[[ "$FILE" == *.ts || "$FILE" == *.tsx ]] && npx prettier --write "$FILE"
exit 0

Save that as a script, point the hook's command at it (the ${CLAUDE_PROJECT_DIR} placeholder resolves to your project root, so committed hooks work on everyone's machine), and formatting stops being something you review for.

Hook #2: block the commands you never want run

PreToolUse fires before a tool call, and this is where exit codes get interesting. A hook that exits with code 2 blocks the action, and whatever the script printed to stderr is fed back to Claude as the reason — so the agent doesn't just fail, it understands why and adjusts course:

#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qE 'rm -rf|--force'; then
  echo "Destructive command blocked by policy" >&2
  exit 2
fi
exit 0

Wire that to PreToolUse with a Bash matcher and you have a guardrail that no amount of context drift can talk its way past. The exit-code contract is simple: 0 means proceed, 2 means block and explain, anything else is a non-blocking error that shows up in the transcript but doesn't stop the run. The same trick works for protecting files — match on Edit|Write and exit 2 when the path is .env, a lockfile, or a production config.

Hook #3: know the moment Claude stops needing you — or starts

The two events most people discover last are the ones with the biggest quality-of-life payoff. Stop fires when Claude finishes responding — the task is done. Notification fires when Claude Code is trying to get your attention, and it tells you why: the matcher value permission_prompt means Claude is blocked waiting for your approval, and idle_prompt means it's been sitting idle waiting for input.

Why does that matter? Because a real Claude Code task runs for minutes, and the expensive failure mode isn't the agent being slow — it's the agent being done (or blocked on a permission prompt) while you're off in another window. We wrote a whole post on not watching the terminal; hooks are the mechanism that makes it possible. A first version can be one line on macOS:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Glass.aiff"
          }
        ]
      }
    ]
  }
}

That works, but you'll outgrow it fast: a sound doesn't tell you which session finished when you're running several in parallel, doesn't distinguish "done" from "waiting for permission", and isn't clickable. We built AI Done Now because we kept rebuilding this exact hook setup on every machine — it's a Mac menu bar app that handles the wiring for you and shows native, clickable notifications with distinct alerts for "finished" and "needs your input", for Claude Code and other agent CLIs.

Gotchas worth knowing before you ship a hook

A few things that save you a debugging session:

  • Hooks run with your full user permissions. They're arbitrary shell commands executing automatically — review any hook you copy from the internet, and be doubly careful with hooks committed to shared repos.
  • Set timeouts on slow commands. Command hooks get a generous default timeout (600 seconds), which means a hung script can stall your whole session. Add a per-hook timeout value for anything that touches the network.
  • Stop hooks can do more than notify. A Stop hook that exits 2 actually prevents Claude from stopping — people use this to enforce "don't finish until the tests pass". Powerful, but add an escape hatch or you can loop forever.
  • Read the payload from stdin. Every hook receives JSON describing the event — session ID, working directory, tool input. jq is your friend.

Start with one

Hooks reward incrementalism. Pick the one that stings most — formatting noise in diffs, a command you're scared of, or finding out ten minutes late that Claude finished — and wire up just that. Once the first one quietly does its job for a week, you'll know exactly which hook to add next. And if the one you want is "tell me when it's done", that's the one you don't have to build: AI Done Now handles Claude Code notifications out of the box.

Keep reading

Desk Exercises for Programmers: 15 Moves to Do While Your AI Agent Codes

7 min read

Exercise While Coding: Turn Claude Code Wait Time Into Micro-Workouts

7 min read

Claude Code Notch Notifications on Mac: See When Claude Is Done Without Watching the Terminal

7 min read

Claude Code Tips and Tricks: 12 Ways to Use Claude Code Effectively

8 min read

Claude Code Multiple Sessions: How to Run Agents in Parallel Without Losing Track

6 min read

A Claude Code Workflow That Doesn't Involve Watching the Terminal

5 min read

Claude Code Auto Mode: Fewer Permission Prompts Without Living Dangerously

7 min read

Claude Code Subagents: How to Delegate Work to Specialized Agents

7 min read

Claude Code Context Management: Treat the Context Window Like a Budget

6 min read

Per-Subagent Model Selection: Route the Grunt Work Down, Keep the Judgment Up Top

7 min read

Skills and Plugins: How to Teach Claude Code Your Way of Working

7 min read

Claude Code Background Tasks: Run Long Commands Without Blocking Your Session

6 min read

Codex CLI Notifications: How to Get a Ding When Codex Is Done or Needs Input

7 min read

Cursor Notification When Done: Every Way to Get Notified When Cursor Finishes

6 min read

Claude Code Notifications: How to Get Notified When Claude Code Finishes or Needs Your Input

6 min read

Want to Be Notified When Claude Responds? How Claude Notifications Work on Web, Desktop, and Mobile

5 min read

Claude Code Notification Scripts: Copy-Paste Recipes for Every Platform

6 min read

Get a Ding the Moment Codex Needs Your Response

6 min read

Get Notified the Moment Claude Code Is Waiting for Your Input

6 min read

“Notifications Are Turned Off for Claude” — Here Is the Fix

6 min read

Codex Sound When Done: Make Codex CLI Play a Sound When It Finishes

6 min read

terminal-notifier + Claude Code: Native macOS Alerts When Your Agent Finishes

6 min read

Gemini CLI Notifications: How to Get a Sound or Alert When Gemini Finishes

6 min read

Get Claude Code Notifications on Your Phone

6 min read

Claude Code Remote Control, Explained

7 min read

preferredNotifChannel: Claude Code's Built-In Notification Setting

6 min read

Claude Code Notifications in tmux and Over SSH

7 min read

Claude Code Effort Levels: Why Your Setting Keeps Getting Ignored

8 min read

Codex vs Claude Code Notifications: How Each One Tells You It Is Done

8 min read

Claude Code Notifications Not Working: A Diagnostic Checklist

10 min read

Claude Code Notifications Inside Your Editor's Terminal

7 min read

CLAUDE_CODE_DISABLE_BACKGROUND_TASKS Explained

7 min read

CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP Explained

8 min read

Cursor Alerts Explained: Every Alert Cursor Raises, and How to Control Them

7 min read

Claude Code Environment Variables: The Groups That Actually Matter

10 min read

Claude Code Notifications on WSL and Windows

9 min read

Claude Code Checkpoints and /rewind

8 min read

Claude Remote Control: How It Works, Turning It Off, and Auto Mode

7 min read

Claude Code /loop: Poll a Deploy, Babysit a PR, and Get Told When It's Done

8 min read

Setting Up NotchFit With OpenAI Codex CLI: Hooks, $notchfit-plan, and the Daily Flow

7 min read

Claude Mods Explained: What the New Plugin Layer Can Do, and How to Turn On 'You Should Know'

9 min read

NotchFit vs Mac Break Reminder Apps: A Clock or a Signal From Your Coding Agent?

8 min read

Claude Code Headless Mode: Running claude -p in Scripts and CI, and the Three Signals That It Finished

10 min read

Building a Movement Habit at a Desk: Use the Agent Run as the Cue, One Set as the Unit, and Streaks Carefully

8 min read

Claude Code MCP Servers Explained: Adding Servers, Choosing a Scope, Handling Secrets, and Why Long Tool Calls Go to the Background

10 min read

/notchfit:plan Explained: How Claude Code or Codex Writes a Weekly Workout Plan the Notch Can Actually Run

8 min read

Claude Code Spinner Verbs Explained: What “Pondering” and “Brewing” Mean, How to Change Them, and Why You Should Stop Watching the Spinner

7 min read

Why NotchFit's Done and Permission Alerts Wait Until Your Set Ends, When That Costs You, and How to Turn the Workout Off

7 min read

How to Resume a Claude Code Session: --continue vs --resume, Naming Sessions, the Session Picker, Branching, and What Comes Back

9 min read

NotchFit on a Mac Without a Notch: How Pill Mode Works on Mac mini, iMac, Mac Studio and a MacBook With the Lid Closed

6 min read

How to Run a Claude Code Session in the Background: /background, claude --bg, Agent View, and Getting Back to It

9 min read

What a Notch App Can See: NotchFit's Local-First Design, What the Claude Code and Codex Hooks Send, and What Stays on Your Mac

7 min read

Why Codex CLI Asks for Permission Every Time, and How to Tune the Sandbox and Approval Policy Without Going Full Access

8 min read

What to Do While Claude Code or Codex Works: A Simple Protocol for the Two-to-Twenty-Minute Gap in Every Agent Run

7 min read

Is It Possible to Get a Notification When Claude Code or Codex Hits a Reset? Yes for Claude Code: the quota_auto_resume Hooks, Explained

8 min read

What a MacBook Notch App Can Actually Do: The Five Kinds of Notch Utility, Their Trade-offs, and Where NotchFit Fits

7 min read

How to Make MCP Servers Not Take Up as Much Context in Claude Code: Tool Search, alwaysLoad, Scopes and Output Caps

8 min read

The notchfit Command Line: Drive Your Workout, Read Status as JSON, Validate Plans and Test the Notch Without Leaving the Terminal

7 min read

How to Audit MCP Tool Calls Made by Claude Code: A Five-Minute Hook Audit Log, OpenTelemetry Tool Events, and the Transcript for Investigations

9 min read

Exercise Snacks: What the Research Actually Says About One-Minute Vigorous Breaks, What It Does Not, and How NotchFit's Agent-Run Sets Compare

8 min read

How Long Until a Claude Code MCP Tool Call Times Out? The Four Timers (Startup, Two-Minute Backgrounding, Idle, Wall-Clock), Their Defaults, and Which One to Change

8 min read

Sitting Too Long as a Developer: The Posture Problems Coding Agents Made Worse, What the Research Says About Breaking Up Sitting, and How NotchFit Turns an Agent Run Into the Break

8 min read

Claude Code .mcp.json Explained: Where Project-Scoped MCP Servers Are Read From, What Happens in Subfolders and Monorepos, and Why a Committed Server Shows Pending Approval

8 min read

Standing Desk Exercises for Developers: Why Standing Still Is Not the Goal, Eight Movements That Fit a Thirty-Second Agent Run, and How NotchFit Cues Them From the Notch

8 min read

The claude mcp Command Reference: add Syntax by Transport, What --scope local, project and user Actually Mean, add-json and add-from-claude-desktop, list, get, remove, login and serve

9 min read

Your First Week With NotchFit: Install and Simulate, Run Real Tasks, Write a Smaller Plan Than You Want, Tune the Alerts, Survive the First Skipped Day, and Decide What Stays

8 min read

How to Stop a Running Claude Code Task: Esc vs Ctrl+C, Background Tasks, Subagents, and Disconnecting Remote Control

8 min read

Pomodoro vs Agent-Driven Breaks: Timing Movement to Claude Code and Codex Runs Instead of a Timer

7 min read

Claude Desktop MCP Configuration: claude_desktop_config.json, Logs, Extensions, and the Difference From Claude Code

9 min read

The 20-20-20 Rule for Developers: Eye Strain, the Evidence, and Agent Runs as the Cue

8 min read

Claude Agent SDK + MCP Servers: mcpServers, allowedTools, Status Checks and Auth

9 min read

Discreet Desk Exercises for an Open-Plan Office While Claude Code Runs

7 min read

claude remote-control Server Mode: Run Claude Code as a Session Server

9 min read

Wrist and Forearm Stretches for Developers: A 60-Second Routine for Every Claude Code Run

7 min read