Curriculum › Claude Code Configuration & Workflows · 20% of the exam

Hooks and workflow automation

What you'll be able to do

  • Configure a PreToolUse or PostToolUse hook to enforce a team policy
  • Explain why a hook is more reliable than an instruction for a hard rule
  • Distinguish Claude Code's product-level hooks from an Agent SDK's lifecycle hooks
  • Design a hook that blocks safely without breaking legitimate work

What you’ll be able to do

  • Configure a PreToolUse or PostToolUse hook to enforce a team policy
  • Explain why a hook is more reliable than an instruction for a hard rule
  • Distinguish Claude Code’s product-level hooks from an Agent SDK’s lifecycle hooks

What you need to know

A hook is enforcement outside the model’s judgment

Claude Code hooks are shell commands configured in settings.json that run at defined points in the tool-use lifecycle — before a tool runs (PreToolUse), after one completes (PostToolUse), and other lifecycle points. A PreToolUse hook can inspect a proposed command and block it before it executes; a PostToolUse hook can run after a file edit to lint it or log it.

The architectural point is that a hook is deterministic configuration, not an instruction the model has to remember and choose to follow. "Please don't run destructive commands in the production directory" is a request the model is asked to honor every time. A PreToolUse hook that inspects the command and refuses to let it execute is a rule that holds regardless of what the model reasoned its way into wanting to do.

Designing a hook: what to check, and how strict to be

A useful hook is specific about what it blocks and permissive about everything else. A hook that inspects a bash command for a destructive pattern (rm -rf against an unexpected path, a force-push to a protected branch) and blocks only that is enforcing a real policy. A hook that blocks broadly "to be safe" turns into friction that gets disabled the first time it stops legitimate work — and a disabled hook enforces nothing.

before — the rule lives only as a request in CLAUDE.md
## Rules - Never force-push to main
after — the rule is enforced by a PreToolUse hook
settings.json: PreToolUse hook inspects bash commands; blocks any `git push --force` targeting the `main` branch

The CLAUDE.md line is a good reminder. It is not enforcement — nothing stops a session that's reasoned its way to "this force-push is the right call" from making it anyway. The hook stops the command regardless of the reasoning that preceded it.

A different layer from an Agent SDK’s lifecycle hooks

Claude Code's hooks (in settings.json) govern the Claude Code product itself — the interactive coding tool a developer runs. An Agent SDK's lifecycle hooks (covered under Agentic Architecture & Orchestration) govern a custom-built agent application assembled from the SDK. They share a name and a similar before/after shape, but they configure different systems, at different layers, for different audiences — one is a team's IDE-adjacent tool policy, the other is a product architect's runtime guardrail for an application they're shipping to end users.

Key concept

A hook enforces a rule deterministically, outside the model’s judgment — the fix for anything that must never happen, not just something you’d prefer didn’t.

When a scenario describes a hard rule that keeps getting violated despite being stated clearly in instructions, the fix is a hook, not a stronger or more repeated instruction.

Practice scenario

ScenarioA team's CLAUDE.md says "never commit directly to main," but it still happens occasionally when a session reasons that a particular change is small enough to skip the usual branch-and-PR flow.
Work it through, then open this

An instruction in CLAUDE.md is a request the model is expected to honor, and a session that talks itself into an exception will still act on that exception. A PreToolUse hook that inspects git commands and blocks a commit targeting the main branch enforces the rule regardless of the reasoning that preceded it — there’s no “small enough to skip it” exception available once the hook is in place.

Build exercise — Decide instruction versus hook for a set of rules

Intermediate · 20 min

What you’ll learn

  • Sorting team rules into “should be a hook” versus “fine as an instruction”
  • Scoping a hook narrowly enough that it doesn’t block legitimate work
  • Naming the lifecycle point (PreToolUse vs PostToolUse) a given rule needs
  1. List a team’s stated CLAUDE.md rules and mark which ones describe something that must never happen versus something that’s merely preferred.

    • Why: “Must never happen” rules belong in a hook; preferences are fine left as instructions.
    • You should see: At least one rule serious enough to deserve enforcement, not just a request.
  2. For a rule that needs a hook, decide whether it needs to run before the action (to block it) or after (to check or log its result).

    • Why: Blocking a destructive command requires PreToolUse; auditing or linting a completed change fits PostToolUse.
    • You should see: A clear match between the rule’s intent and the lifecycle point it needs.

Exam traps

Writing “never run rm -rf” as an instruction instead of a blocking hook

An instruction can be reasoned around. A PreToolUse hook enforces the rule regardless of the model’s reasoning.

Confusing Claude Code’s settings.json hooks with a custom Agent SDK’s lifecycle hooks

They’re different layers: one governs the Claude Code product, the other governs a custom-built agent application.

Making a hook so aggressive it blocks legitimate, safe operations

An overly broad hook creates friction, gets disabled, and then enforces nothing at all.

Forgetting that a hook is configuration, not something the model can talk itself out of

That’s precisely its value over an instruction — it holds regardless of what reasoning preceded the action.

Sources

Quick check

A monorepo has one root CLAUDE.md that three teams keep editing to add package-specific build steps, causing weekly merge conflicts. What's the architectural fix?