Claude Code hooks for website projects: builds, link checks, formatting and guardrails

By: Irina Shvaya | October 14, 2026
This article is part of our Claude Code Guide: what Claude Code is, how to use it safely on a business website, and how to budget for and choose help. Want it set up for your team? See Claude Code consulting.

A Claude Code hook is a command you set up once that runs automatically at a fixed point in every session: after Claude edits a file, before it runs a shell command, or when it finishes a reply. On a website project, that means you can format every edited file, refuse edits to your build output or environment files, and make Claude run the site build before it tells you the job is done. You don't have to remember to ask, and Claude doesn't get to decide whether to do it.

That last point is why hooks matter. Anthropic's best-practices page puts it plainly: "Unlike CLAUDE.md instructions which are advisory, hooks are deterministic and guarantee the action happens." A line in CLAUDE.md that says "always run the build" is a request. A hook that runs the build is a rule. This guide covers the hooks worth adding to a website repository as of October 2026, how they decide to block something, and the safety rules for hooks themselves.

Key Takeaways

  • Hooks are configured in a hooks block in a settings file. Put team hooks in .claude/settings.json in the repository so everyone gets them; personal ones go in ~/.claude/settings.json.
  • The three events most website teams need are PostToolUse (after an edit: format or lint), PreToolUse (before an action: block it) and Stop (when Claude finishes responding: run the build or a link check).
  • A hook blocks an action by exiting with code 2. Exit code 1 is treated as a non-blocking error, so a guardrail that exits 1 lets the action through.
  • A PreToolUse hook that denies a tool call blocks it in every permission mode, including bypass mode.
  • Command hooks "execute shell commands with your full user permissions." A person should read and test every hook script before it goes into the repository.
  • Run /hooks inside Claude Code to see every hook that is configured, grouped by event.

What a hook is, in three parts

Anthropic's glossary describes a hook at three levels: the hook event, the matcher and the hook handler.

  • Event: the moment in the session when the hook fires, such as PreToolUse (before a tool call runs) or Stop (when Claude finishes responding).
  • Matcher: a filter that narrows when it fires. For tool events, it matches the tool name, so Edit|Write fires only when Claude edits or writes a file, not when it runs a shell command or reads a file. Matchers are case-sensitive.
  • Handler: what runs. Most hooks use "type": "command", a shell command or script. HTTP, MCP tool, prompt and agent hooks also exist; Anthropic labels agent hooks experimental.

When an event fires, Claude Code sends your script a JSON description of what is happening, such as the file path of an edit or the text of a shell command. Your script does its work and answers with an exit code.

The hook events a website team actually uses

The hooks reference lists more than 30 events. Most teams need four or five of them:

EventWhen it firesTypical website use
PostToolUseAfter a tool call succeedsRun a formatter or linter on the file Claude just edited
PreToolUseBefore a tool call executes; can block itRefuse edits to .env files or generated output; refuse risky shell commands
StopWhen Claude finishes respondingRun the site build, a link check or tests before Claude can stop
NotificationWhen Claude Code sends a notification, such as waiting for permissionA desktop alert so you can work on something else during long jobs
SessionStartWhen a session begins or resumes, including after compactionRemind Claude of key project facts after the conversation is summarized

Note that a PostToolUse hook can't undo anything, because the tool has already run. Use PreToolUse for anything you want to prevent.

Where hooks live

Where you put a hook decides who it applies to. ~/.claude/settings.json covers all your projects on your machine only, which suits personal notifications. .claude/settings.json covers one project and can be committed to the repository, which is where team guardrails and build checks belong. .claude/settings.local.json is your private copy for one project, and managed policy settings apply organization-wide. Plugins, skills and subagents can carry hooks too.

Longer hook scripts usually live in a folder such as .claude/hooks/, referenced with the $CLAUDE_PROJECT_DIR variable so the path works for everyone. Ready-made settings files for website teams are in our Claude Code templates.

Hook 1: format every file Claude edits

This is the example in Anthropic's hooks guide. It runs Prettier, a common code formatter, on each file Claude edits or writes. It goes in .claude/settings.json at the project root and needs the jq tool installed:

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}

The check that proves it works: ask Claude to add a line to a JavaScript file using single quotes, then open the file. With Prettier's default settings, the quotes become double quotes. When the hook succeeds, Claude Code shows nothing in the conversation, so look at the file rather than the chat.

The same pattern runs any per-file check your site already uses, such as a linter or a script that checks the internal links in an edited page. One limit: Edit|Write doesn't see files Claude changes through shell commands. The docs suggest a Stop hook that scans the working tree once per turn when you need every change covered.

Hook 2: block edits to protected files and risky commands

A PreToolUse hook runs before the action and can stop it. The hooks guide's example is a script, .claude/hooks/protect-files.sh, that reads the target file path, compares it with a list of protected patterns such as .env, package-lock.json and .git/, and exits with code 2 if one matches. It's registered like this:

"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" }
]
}
]

Claude receives the script's message as feedback, so it can change its approach. To test it, ask Claude to add a comment to your .env file and confirm the edit is refused.

For a website, add the folders you never want edited by hand to that list. When we rebuilt eseospace.com, a publishing step regenerated every post from source files and deleted edits that had been made only in the built copy. A hook that refuses edits to the generated output folder turns that lesson into a rule: edit the source of truth, not the output.

The same kind of hook can watch shell commands. Match Bash and use the if field, which takes permission-rule syntax such as Bash(git *), so your script runs only for git commands. Anthropic calls this filter best-effort and says to use the permission system for a hard allow or deny. Use both: deny and ask rules in settings for the hard line, and a hook for checks a rule can't express. Our guide to permission modes and settings covers the rules side.

One property makes these hooks valuable for a team: "A hook that returns permissionDecision: "deny" blocks the tool even in bypassPermissions mode or with --dangerously-skip-permissions." The reverse isn't true. A hook that says "allow" can't override a deny rule in settings.

The most useful website hook is a gate on finishing. Anthropic's best-practices page describes it: "a Stop hook runs your check as a script and blocks the turn from ending until it passes." On a static or Next.js site the check might be the production build; on any site it might be a link checker run against the built pages.

The script runs your check. If it passes, the script exits 0 and Claude stops normally. If it fails, the script prints the error to standard error and exits 2, which "prevents Claude from stopping" and hands Claude the error so it keeps working. Two cautions from the docs:

  • Claude Code overrides a Stop hook after it blocks eight times in a row with no tool call in between. Have your script read the stop_hook_active field from its input and exit early when it is true, so a check that can never pass doesn't trap the session.
  • Stop fires after every reply, not only when the task is done, so keep the check fast and leave the full test suite to the pipeline described in our guide to GitHub Actions for website QA.

A passing hook proves the build ran, not that the page looks or reads right. A person still reviews the diff and the rendered page; our website QA routine lists what to look at before every deploy.

Exit codes in plain English

Hooks answer Claude Code with an exit code, and a wrong one quietly disables a guardrail:

Exit codeWhat Claude Code doesUse it for
0Success. The action goes aheadChecks that passed, formatting that ran
2Blocking error on events that can block. The message on standard error becomes the reasonGuardrails and gates
Anything else, including 1Non-blocking error when the script prints no JSON decision. The action goes ahead and you see a "hook error" noticeNothing you rely on to stop an action

Anthropic's reference is explicit: "If your hook is meant to enforce a policy, use exit 2." A script with a typo in its path also fails as a non-blocking error, so watch for the notice the first time a new guardrail runs.

Keep the hooks themselves safe

A hook is code that runs on your machine without asking. Anthropic's hooks reference warns: "Command hooks execute shell commands with your full user permissions. They can modify, delete, or access any files your user account can access. Review and test all hook commands before adding them to your configuration." For a website team, that means:

  • A person reads every hook script before it's committed, the same way they would read any other code change. That includes hooks Claude writes for you.
  • Don't put passwords or API keys in hook commands or settings files. HTTP hooks can read environment variables, but only the ones listed in allowedEnvVars.
  • Know the trust rule. In an interactive session, Claude Code holds back hooks until you accept the workspace trust dialog for the folder. In a claude -p script, hooks committed in a repository's .claude/settings.json run without that dialog. Before scripting Claude Code over a repository you didn't write, read its .claude/ folder first.
  • To switch hooks off, set "disableAllHooks": true. Admins can allow only managed hooks with allowManagedHooksOnly.

Hooks are one layer. They sit alongside permission rules, the sandbox and human review, all covered in is Claude Code safe for a live website.

How to add and test a hook

  1. Describe it to Claude. Anthropic suggests prompts such as Write a hook that runs eslint after every file edit or Write a hook that blocks writes to the migrations folder. Change the folder to your build output or uploads directory.
  2. Read what it wrote. Check the event, the matcher and the script line by line. Confirm a guardrail exits 2, not 1.
  3. Confirm it loaded. Run /hooks and find it under the right event.
  4. Trigger it on purpose. Ask for the edit or command it should block, or break the build on a branch and confirm the Stop hook catches it.
  5. Commit it on a branch and have a second person review the pull request, so the hook is shared, versioned and easy to roll back.

Hooks enforce rules. Skills teach Claude a procedure, such as your publishing checklist, and run only when relevant; see Claude Code skills explained. Short reminders still belong in CLAUDE.md, as covered in how to write a CLAUDE.md for a website.

Conclusion

Hooks turn the rules you care about into steps that always run: format the file, refuse the protected folder, pass the build before stopping. Start with one guardrail and one Stop check, test each on purpose, and keep a person reviewing the scripts and the changes they let through. If you want help choosing and testing hooks, permissions and review steps for your team's repository, our Claude Code consulting covers that setup. More guides are in our Claude Code Guide.

Frequently asked questions

Do I need to know how to code to use hooks?

You need someone who can read a short shell script. Claude can write the hook from a plain-English description, but a person has to check what it does before it goes into the repository, because hooks run with your full user permissions.

What's the difference between a hook and a CLAUDE.md rule?

CLAUDE.md is instructions Claude reads and usually follows. A hook is a command Claude Code runs every time the event fires, whatever Claude decides. Use CLAUDE.md for guidance and a hook for anything that must happen with no exceptions.

Can a hook stop Claude from pushing to my live site?

A PreToolUse hook can block git push commands, and its deny holds in every permission mode. Anthropic still recommends permission rules for a hard allow or deny, because the hook's command filter is best-effort. Use an ask or deny rule for pushes, and protect your main branch so changes need an approved pull request.

Why didn't my hook block anything?

The usual causes are an exit code other than 2, a matcher that doesn't match the tool name exactly (matchers are case-sensitive), a script that isn't executable, or a settings file with invalid JSON. Run /hooks to confirm it loaded, then test the script by piping sample JSON into it.

Put this into action with eSEOspace

We help businesses grow with seo, geo & aeo that actually performs. Explore the services behind this guide:

Book a free strategy call →

Get a FREE Audit

We'll perform a comprehensive SEO, AEO, GEO & CRO audit of your website — completely free — and show you exactly how to outrank your competitors.

Don't have a site yet? Get in touch →

Get a FREE GEO/AEO/SEO Audit

We'll analyze your site's SEO, GEO, AEO & CRO — completely free — and show you exactly how to get found across Google and AI answers.

Don't have a site yet? Get in touch →

You Might Also like to Read