CCA-F Exam Blog · Technical Guides

Claude Code Hooks vs CLAUDE.md Instructions: Which Enforces What

Claude Code hooks vs CLAUDE.md instructions: when a rule must be a PreToolUse or PostToolUse hook, when a prompt is enough, and the decision table CCA-F uses.

Updated

Use a Claude Code hook when a rule must hold every time and a program can check it; use a CLAUDE.md instruction when the rule is a preference, a matter of judgment, or something only the model can evaluate. CLAUDE.md is probabilistic guidance the model can override; a hook is code that runs before or after a tool call and can block, modify, or transform it deterministically.

That single distinction, prompt enforcement versus programmatic enforcement, is one of the most heavily tested ideas on the Claude Certified Architect – Foundations exam. It sits in Domain 1 (Agentic Architecture & Orchestration, 27%) under hooks and enforcement, and it leaks into Domain 3 whenever a scenario involves CLAUDE.md.

Why do CLAUDE.md instructions fail even when they are clear?

Not because the model misreads them. It fails when it decides, in context, that the instruction should not apply. Production examples from the study material: “always confirm before rm/drop/truncate” is skipped when the user says “clean up the project,” because confirmation looks redundant; “verify identity before accessing the account” is skipped when the customer already volunteered an account number; “run the full test suite” becomes “run unit tests” under time pressure. Measured miss rates land in the 4–15% range, and stronger wording (“MANDATORY”, “UNDER NO CIRCUMSTANCES”) barely moves them, because the failure is a judgment call, not a comprehension gap.

The exam frames this as the deliberate-override problem. In one dataset, 11% of discount-limit violations broke down as 5% misidentified tiers (a fixable bug) and 6% cases where the model correctly identified the tier and then chose to exceed it for a frustrated customer. No prompt fixes the second half. See the model will override your instructions.

What can hooks actually do?

Claude Code and the Agent SDK expose five lifecycle hooks. Two of them are where enforcement lives.

HookFiresCan doCannot do
SessionStartOnce at startLoad config, seed contextPer-call checks
UserPromptSubmitEach user messageInject context, sanitize inputTouch tool calls
PreToolUseBefore a tool runsDeny, allow, or allow with modified inputsTransform outputs
PostToolUseAfter a tool runsNormalize, redact, log resultsPrevent execution
SessionEndAt shutdownCleanup, archiveAnything mid-session

A minimal Claude Code configuration that blocks destructive shell commands looks like this in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "python .claude/hooks/block_destructive.py" }
        ]
      }
    ]
  }
}

The script reads the tool call as JSON on stdin and prints a decision. The three legal outcomes:

{ "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "rm -rf outside /tmp is blocked. Move the target to /tmp/trash instead." } }
{ "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "updatedInput": { "file_path": "/sandbox/src/main.py" } } }

Returning nothing (or an empty object) means “proceed unchanged.” Two bugs account for most broken hooks: logging “Blocked!” inside an if and then falling through to an empty return, which always allows; and returning updatedInput without an explicit allow, which is silently ignored. Only deny and allow are valid values; block, reject, and exceptions are not, and an exception may default to allowing. Give the model a reason and a redirect in every deny so it can take the alternative path instead of retrying blindly. Full details in PreToolUse return values and the five hook types.

Matchers are regexes and match substrings, so update catches get_status_update. Anchor enforcement hooks (^update_account$), and remember MCP tools carry a prefix (mcp__payments__process_refund), so a bare process_refund matcher lets the MCP variant through. Omit the matcher only for universal concerns like audit logging. See HookMatcher registration.

When must a rule be a hook? The three-axis test

The study material reduces the choice to three questions:

  1. Consequence. Does a miss have legal, financial, security, or data-integrity impact?
  2. Verifiability. Can code check compliance deterministically (regex, list, threshold, path)?
  3. Subjectivity. Does the rule need judgment (“be empathetic,” “present balanced views”)?

Consequence high and verifiable means hook. Subjective means prompt, regardless of consequence, because code cannot evaluate it. Low consequence means prompt, because building a hook is over-engineering. The compliance rate is not one of the axes.

RuleConsequenceVerifiableSubjectiveMechanism
Block refunds over $500FinancialYesNoPreToolUse hook
Never write outside src/ in CIData integrityYes (path check)NoPreToolUse hook
Redact SSNs from tool outputLegalYes (regex)NoPostToolUse hook
Normalize timestamps to ISO 8601CorrectnessYesNoPostToolUse hook
Log every tool call for auditComplianceYesNoPre + Post, no matcher
Add input validation on public API functionsSecurity in api/public/, advisory elsewhereYesNoContext-aware hook by path
Use camelCaseStyleYesNoCLAUDE.md
Follow the suggested report outlineFormatPartlyPartlyCLAUDE.md
Use professional, empathetic toneQualityNoYesCLAUDE.md
Convert measurements to metricDepends on audienceYesYesCLAUDE.md

Two rows deserve a note. Timestamps and currencies have objective conversion rules, so a PostToolUse hook is right and, in one deployment, cut date-comparison errors from 12% to 0.3%. Measurements depend on context (a US market report may intentionally use imperial), so that stays a prompt even though the conversion is mechanical. See select by consequence and verifiability and PostToolUse normalization.

Isn’t a hook plus an instruction redundant?

No, and the exam likes this one. A hook that blocks production deploys and a CLAUDE.md line saying “never deploy to production without human approval” do different jobs. The hook guarantees the outcome. The instruction reduces attempts, so the model asks for approval instead of hitting a wall. Both together is defense in depth: the hook catches known patterns deterministically, the prompt is a probabilistic net for novel ones the regex missed. Deleting either makes the system worse.

What about over-hooking?

The failure mode in the other direction is real. One team, after a few incidents, hooked everything: citation style, word counts, paragraph length, vocabulary. Reports triggered a dozen denials each, most for style, and production time tripled because a 501-word section forced a rewrite. The fix was to keep hooks for compliance (source verification, citation accuracy) and move style back to CLAUDE.md.

The related discipline: diagnose before you migrate. If test-before-commit compliance dropped from 97% to 82%, ask why. If the model is reasoning “this small change doesn’t need tests,” that is the judgment failure and a hook is warranted. If the instruction is simply buried in an overgrown CLAUDE.md, restructuring the file is the cheaper fix. Our post on how to write CLAUDE.md covers the file-side half of that decision.

What is the exam really testing?

CCA-F questions in this area almost always present a rule that is being violated some percentage of the time and offer four responses: reword the instruction more forcefully, add retries, add a hook, or add a hook and remove the instruction. The rewarded reasoning is: identify the consequence, check whether code can verify it, and pick the deterministic mechanism for high-consequence verifiable rules while leaving subjective and low-stakes rules as prompt guidance. Recognize the distractor patterns too: PreToolUse proposed for output redaction (impossible, outputs do not exist yet), SessionStart proposed for per-call validation (fires once), a single catch-all hook proposed as “simpler” (mixes concerns and fires on every call), and “the hook makes the instruction redundant.”

Next step

Work through the hooks and enforcement articles in the Domain 1 study guide (Tasks 1.4 and 1.5), then try the Domain 1 practice questions to see how the three-axis test is disguised in scenarios. When you are ready, the free 60-question mock exam weights Domain 1 at its official 27%. Confirm exam logistics such as the US$125 fee and 120-minute format on the official Anthropic / Pearson VUE page before you register.

Frequently asked questions

If I add a hook, should I delete the matching CLAUDE.md instruction?

expand_more

Usually keep both. The hook is the deterministic safety net; the instruction reduces how often the model even attempts the blocked action, which means fewer denials and smoother sessions. One line of prompt text costs almost nothing.

Can a PreToolUse hook change what a tool writes?

expand_more

It can change the tool's inputs before execution, such as redirecting a file path to a sandbox, by returning permissionDecision: allow together with updatedInput. It cannot touch outputs, because they do not exist yet; that is PostToolUse's job.

Why does the exam say a rule with 99% compliance still needs a hook?

expand_more

Because selection is by consequence, not by rate. A 1% miss on a data-privacy rule is a legal incident; a 4% miss on greeting a customer by name is nothing. Compliance percentage alone never decides the mechanism.

Put it into practice

Take the free 60-question Claude Certified Architect mock exam, or work through the CCA-F study guide domain by domain.

Certified Architect is an independent, community-built study site. Exam facts reflect public Anthropic / Pearson VUE information and can change — always confirm on the official pages before registering.

Related articles