LEARN · PHASE 14 · LESSON 96

Guardrails vs Instructions — Requests vs Enforcement

After this lesson you can tell a request from a wall, and convert the rules

Type
Learn
Prerequisites
Phase 08, Lesson 55 (what a hook is) and 58 (exit-1-vs-2); Phase 04, Lesson 33 (permissions)
Time
~30 minutes

Learning Objectives

  • Tell a request (context) from an enforcement (mechanism)
  • Convert a must-never rule into a hook or a permission rule
  • Explain why instructions can be overridden and guardrails cannot
  • Place each guardrail where it actually fires

The Problem

This repo's own brief says: one agent, one branch; never force-push; commit before you exit. An agent that had read the file still force-pushed. The prose was in its context window — it just weighed the instruction against a task that said "clean up the branch" and lost.

The instruction had no wall behind it. The mechanism that would have blocked the command — a hook — was never installed.


The Concept

There are two layers, and they are not the same kind of thing.

Instructions are natural-language text in the context window: CLAUDE.md, AGENTS.md, the system prompt, the task. They steer the model. They are cheap, flexible, and carry no guarantee. The model may comply, and under a competing instruction it may not.

Guardrails are mechanisms outside the model: a hook (Lesson 55), a permission rule (Lesson 33), a sandbox, a git protection. The model can still propose the action, but the mechanism decides whether it runs.

flowchart LR
    M["model proposes an action"] --> G{"guardrail check<br/>(hook / permission)"}
    G -- allow --> T["tool executes"]
    G -- block --> B["action denied,<br/>reason returned"]
Mermaid source — renders as a diagram where mermaid.js is available

A hook's exit code carries the veto: from Lesson 58, one code blocks the call and returns the reason, another only reports an error without blocking. That distinction is what makes a hook a wall rather than a complaint.

The reframe: You cannot instruct a wall into existence — enforcement is a

mechanism the model cannot talk its way through.

The practical consequence: keep both. The instruction keeps the model from even proposing the action, which is cheaper and clearer. The guardrail is the guarantee for the day the instruction loses.

Which rules become walls? The ones where the cost of a single failure is unacceptable: force-push, writing to main, deleting without a commit, sending to production.


Build It

  1. List the "never" rules you currently rely on.
  2. For each, ask: if the model ignored this, what would stop it? If the answer is "nothing," it is a request.
  3. Pick the most dangerous one and convert it into enforcement — a PreToolUse hook that matches the command and exits with the blocking code from Lesson 58, or a permission deny rule.
  4. Test it: ask the agent to do the forbidden thing. The guardrail must fire and the action must not happen.
  5. Keep the instruction as well, and note in writing that the hook, not the sentence, is the guarantee.

Step 4 is the only proof that matters.


Use It

Command / conceptWhen you reach for it
Instruction / requestWhen you want to steer behaviour cheaply
Guardrail / enforcementWhen a single failure is unacceptable
PreToolUse hookWhen a specific action must be blocked before it runs
Permission deny ruleWhen a whole tool or path should never be reachable
Exit-code veto (Lesson 58)When you need the hook to actually stop the call, not just warn

Exercises

  1. Classify five of your rules as request or enforcement, with a reason. ✅ You pass when each rule is labelled and the enforcement ones name the mechanism that fires.
  1. Convert one request into a guardrail and prove it blocks. ✅ You pass when the forbidden action is attempted and does not happen.
  1. State, in one sentence each, what the instruction adds that the guardrail does not. ✅ You pass when the sentence names steering (the model avoids proposing the action) rather than enforcement.

Key Terms

TermWhat people sayWhat it actually means
instruction"a rule the agent follows"natural-language text in the window that the model may or may not obey
guardrail"a rule the agent follows"a mechanism outside the model that allows or blocks the action
hook"a script that watches the agent"code that runs on a loop event and can veto a tool call (Phase 08)
deny rule"a permission setting"configuration that makes a tool or path unreachable
exit-code veto"the hook returns an error"the specific exit code that blocks the call rather than only reporting one (Lesson 58)

What this lesson skipped

The full hook event list is Phase 08, Lesson 56. Permission modes are Phase 04, Lesson 33. Sandboxing is Phase 17, Lesson 114. Hook behaviour and exact exit-code semantics are version-gated — verify them against https://code.claude.com/docs/llms.txt and date any claim you repeat.

Check yourself

4 questions. Answer before you reveal — recognising the right option is not the same as being able to produce it.

  1. CLAUDE.md says 'never edit files under /vendor.' An agent edits them anyway. What do you add?

    1. A stronger sentence in CLAUDE.md
    2. A PreToolUse hook or permission deny rule for that path
    3. A bigger model
    4. More context about why /vendor is off-limits
    Show answer

    B. A PreToolUse hook or permission deny rule for that path

    The instruction already failed, so adding more instruction is the same layer failing again. A mechanism outside the model stops the edit regardless of what the model decides. 'A stronger sentence' is tempting because it feels more forceful, but emphasis does not change the fact that it is still a request.

  2. Which of these is a guardrail rather than an instruction?

    1. A line in AGENTS.md that says 'one agent, one branch'
    2. A system prompt stating 'do not force-push'
    3. A PreToolUse hook that blocks git push --force
    4. A reminder in the task description
    Show answer

    C. A PreToolUse hook that blocks git push --force

    Only the hook runs outside the model and can veto the action. The other three are text the model weighs and may override. The tempting answer is the system prompt, because it sounds authoritative — authority in the window is still just a request.

  3. You already have a hook that blocks force-push. Why keep the instruction too?

    1. Because the hook is unreliable
    2. Because the instruction keeps the model from proposing the action at all, which is cheaper and clearer — the hook is still the guarantee
    3. Because the hook will not fire without it
    4. You should not; the hook replaces the instruction
    Show answer

    B. Because the instruction keeps the model from proposing the action at all, which is cheaper and clearer — the hook is still the guarantee

    Instructions and guardrails do different jobs: the instruction steers, the guardrail enforces. Keeping both avoids needless blocked calls while preserving the guarantee. 'The hook will not fire without it' is tempting but false — a hook fires on the event, not on the prose.

  4. A hook is meant to block a dangerous command but the command runs anyway. Which detail should you check first?

    1. Whether the model is large enough
    2. Whether the hook exits with the code that blocks, rather than the code that only reports an error
    3. Whether the prompt is clear
    4. Whether the context window is full
    Show answer

    B. Whether the hook exits with the code that blocks, rather than the code that only reports an error

    From Lesson 58, only one exit code blocks the call; the other reports an error without stopping it — the classic exit-1-vs-2 trap. The tempting answer reaches for model size, but a hook that returns the wrong code is a wall with no door.