Skip to main content
Claude codeHooksAgent promptsAi agents

Claude Code Hooks: Map Your Risk Profile to the Hooks You Actually Need

Design Claude Code hooks with a policy prompt that maps your project's risk profile to the lifecycle events to guard and what each hook should enforce.

PPromptsCart Team·July 20, 2026·Updated July 20, 2026·7 min read

What Claude Code Hooks Are For

Claude Code hooks are shell commands that run automatically on lifecycle events (PreToolUse, PostToolUse, Stop, and others), giving you deterministic control over an agent's behavior. They fire as commands, not as model prompts, which is the whole point: the model can't forget a hook, can't decide to skip it because the conversation got long. They live in .claude/settings.json for the team or .claude/settings.local.json for you.

Most guides explain the events and hand you example shell commands: the paul-schick PreToolUse/PostToolUse tutorial, the claudefa.st 12-events guide, the ClaudeLog hooks mechanics page. paul-schick's advice is typical and sensible: "start with three hooks." What none of them give you is a way to derive which hooks your specific project needs from what your project can actually damage.

Why "Start With Three Hooks" Isn't Enough

The three-hook starter (block rm -rf, protect .env, auto-format on edit) is a fine default. It's also generic. Your project isn't generic. A repo with production migrations needs a hook the starter set never mentions. A repo that calls a paid API needs a spend guard. A repo with a generated/ tree needs that path protected, not .env.

The right question isn't "what are the common hooks." It's "what can Claude damage here?" That's a risk question, and risk is local. The official Claude Code memory docs make the boundary explicit: CLAUDE.md is context the model tries to follow, while a hook is enforcement that "applies regardless of what Claude decides." If a rule must hold every time, it's a hook, and which rules those are depends on your repo, not a starter list.

Hooks enforce; instructions suggest

A CLAUDE.md line like "never edit generated files" is a request the model usually honors and occasionally doesn't, especially deep in a long session. A PreToolUse hook that returns a non-zero exit code on any Edit under generated/ blocks it every time, deterministically. Use instructions for guidance, hooks for the rules you can't afford the model to miss.

The Policy Contract a Prompt Fills

Instead of copying someone's three hooks, a policy prompt maps your risk profile to a hook plan against a fixed contract:

  • Risk inventory. What can go wrong here: data loss, secret exposure, runaway cost, broken production, unreviewed dependency changes.
  • Event mapping. Each risk assigned to the lifecycle event that catches it: destructive commands and protected paths to PreToolUse, formatting and test runs to PostToolUse, scope checks to UserPromptSubmit.
  • Enforcement per hook. What each hook does: block (non-zero exit), transform, or log. A block is a wall; a log is a paper trail. Don't confuse them.
  • Shared vs local split. Which hooks belong in the committed settings.json (team policy) and which in the gitignored settings.local.json (your machine).

That mapping, risk to event to enforcement, is exactly what the tutorials skip and the prompt produces.

Shared Hooks vs Personal Hooks

The split between .claude/settings.json and .claude/settings.local.json isn't cosmetic. The committed file is team policy: every developer on the repo gets the same blocks and formatters, which is what you want for "never force-push to main" or "format Python with ruff on save." The gitignored local file is yours: a noisy logger you're using to debug a workflow, a personal block on a directory only you keep wandering into.

Getting this wrong creates friction. Put a personal experiment in the shared file and you've inflicted it on the whole team. Put a real safety rule only in your local file and a teammate's agent runs unguarded. The rule of thumb: if breaking the rule would hurt anyone on the team, it's shared; if it's about your own habits, it's local.

A generated hook policy can label each hook with its intended file, so the split is a decision you make once rather than a thing you sort out after a teammate complains. That labeling is cheap to produce and annoying to retrofit.

How to Generate Your Hook Policy, Step by Step

1. Inventory the risks

Walk the repo and name what Claude could break: which paths are sacred, which commands are destructive, which operations cost money or hit production.

2. Fill the variables

The prompt takes {{risk_profile}} (the inventory) and {{stack}} (so the example commands fit your tooling, prettier vs ruff, pnpm vs cargo).

3. Run it against the contract

You get a hook plan: each risk mapped to an event, each event with a concrete enforcement and the settings file it belongs in.

4. Wire and test

Add the hooks to .claude/settings.json, then deliberately trigger one. Try a blocked command, and confirm the non-zero exit actually stops it.

One Opinion: Most Teams Over-Block and Under-Log

Here's a stance worth defending. Teams new to hooks reach for blocks everywhere, block this, block that, and end up fighting their own agent, approving past walls all day. Blocking is right for the genuinely destructive: rm -rf, force-push to main, editing secrets. For everything else, a PostToolUse log is usually the better tool.

A log tells you the agent touched the migrations folder without stopping it mid-task, so you review the diff instead of babysitting every step. Reserve blocks for what you can't undo. Log what you want to know about. The split between "stop this" and "surface this for review" is the actual design work, and it's the same Always / Ask-first / Never thinking behind a good guardrails prompt for AI coding agents.

Variables You'll Set

VariableRequiredWhat it is
{{risk_profile}}YesWhat Claude can damage: protected paths, destructive commands, cost or prod risks
{{stack}}YesTooling, so the hook commands fit (ruff vs prettier, cargo vs pnpm)
{{enforcement}}NoPer-risk preference for block vs log vs transform

Getting Started

  1. Inventory what Claude can break in this repo.
  2. Decide, per risk, whether you need a wall or a paper trail.
  3. Feed {{risk_profile}} and {{stack}} to a policy prompt with a fixed contract.
  4. Wire the resulting hooks into .claude/settings.json and settings.local.json.
  5. Trigger a blocking hook on purpose to confirm it stops the action.

The boundary logic behind hooks is the same as a system-prompt guardrail, so the Coding Agent Guardrails System Prompt produces the Always / Ask-first / Never tiers your hook policy should mirror. If you're enforcing the same rules in CI rather than at the agent's tool calls, the AI PR CI-Gate Harness Agent Pack moves the gate to the pull request.

Browse the prompt packs

Why deterministic enforcement is worth the setup

The model's reliability degrades as context fills. An instruction it followed at turn three can slip at turn thirty. Hooks don't degrade. A PostToolUse formatter runs on the thousandth edit exactly as it ran on the first. For anything you'd be annoyed to find skipped, that consistency is worth the few lines of settings.json. It's the one layer in an agent setup the model genuinely can't talk its way around.

Skip the setup

The Coding Agent Guardrails System Prompt turns a {{risk_profile}} into an explicit Always / Ask-first / Never policy, the exact mapping your hook plan needs, in a form Claude also reads as a ## Boundaries block at the instruction layer. It's part of The Complete AI Prompts Bundle, a one-time lifetime license to the whole catalog plus every pack added later, worth it if you guard more than one repo or agent.

Get the Guardrails System Prompt

Hooks are the deterministic floor under an agent's behavior. Map your real risks to events, block what you can't undo, log the rest. For the instruction-layer companion and the CI-layer one, see Claude Code subagents system prompts and an AI CI gate prompt to block risky PRs.

FAQ

Common questions

What are Claude Code hooks?
Claude Code hooks are user-defined shell commands that run automatically on specific lifecycle events — PreToolUse, PostToolUse, UserPromptSubmit, Stop, and others. They fire deterministically as shell commands, not as model prompts, so they enforce rules with reliability the model can't undermine. They live in .claude/settings.json (shared) or .claude/settings.local.json (personal).
What's the difference between PreToolUse and PostToolUse hooks?
A PreToolUse hook fires before Claude Code runs a tool like Bash, Edit, or Write, so it's where you block dangerous commands or protect files — return a non-zero exit code to block the call entirely. A PostToolUse hook fires after a tool completes, so it's where you run a formatter, a test, or a logger on what just changed.
Why use hooks instead of CLAUDE.md instructions?
CLAUDE.md is context the model reads and tries to follow, with no guarantee of compliance, especially on long conversations. Hooks are shell commands that fire on fixed events regardless of what the model decides. If a rule must run every time — format on save, block a destructive command — a hook enforces it deterministically where an instruction only suggests it.
Stop reading. Start shipping.

Get the prompt packs this guide is built on

Ready-to-paste prompts with documented variables and worked examples for ChatGPT, Claude, and Gemini. One-time payment, own it forever.