Model-driven decision-making - letting Claude decide which tool to call and when - is the default that makes agents flexible, and it's usually the right default: the model adapts to situations you never explicitly mapped out. It has one important exception. Where business logic demands deterministic compliance - a financial threshold, a required approval, a regulatory check - programmatic enforcement should override model discretion rather than relying on the model to remember and apply the rule correctly on every single call. The decision isn't about whether the model is usually reliable enough; it's about whether the consequence of one single failure justifies a deterministic guarantee instead of a probabilistic one.
The decision framework
If a single failure would cost real money, create legal or regulatory exposure, or do something irreversible - use a code-level gate. If it's a formatting preference, a style guideline, or something where occasional deviation genuinely doesn't matter - prompt-based guidance is fine, and adding a hard gate there is unnecessary overhead for no real benefit. A prompt like "always check the approval before proceeding" might work 95%+ of the time; for a compliance rule, that remaining failure rate is exactly the exposure a code-level gate exists to close. The gate doesn't need the model to be unreliable to be justified - it needs the failure cost to be high enough that even rare deviation is unacceptable.
Where the gate has to live: before execution, not after
A gate that runs before a tool executes - intercepting the requested tool call, checking it against a hard-coded rule, and blocking or redirecting it if it fails - can actually prevent a non-compliant action from happening. A check that runs after a tool has already executed can only detect and flag a violation that's already occurred; by the time it fires, the refund has already been issued or the transfer has already gone through. Both have legitimate uses - pre-execution checks for prevention, post-execution checks for normalisation and audit trails - but only pre-execution checks are enforcement in the sense a compliance requirement needs. If the Agent SDK's PreToolUse/PostToolUse hook naming is available to you, that's exactly the distinction those two hook points encode; if you're building against the raw Messages API, the equivalent is simply where in your own loop code you place the check relative to actually calling the tool's implementation.
Common exam distractor
Proposing a check that runs after the sensitive action has already executed - flagging it for review, logging it, queuing it for audit - as the fix for a hard compliance requirement is treating detection as if it were prevention. Post-hoc detection is valuable for catching what slips through, but it does not stop the non-compliant action from having happened. A requirement that must never be violated needs a pre-execution gate.
A rejected call still needs a tool_result
When a gate blocks a tool call, the rejection still has to come back to the model as a proper tool_result - with a clear explanation of why it was blocked - rather than the loop just silently dropping the call or breaking. Two reasons this matters: structurally, the API requires a tool_result for every tool_use_id in the previous assistant turn, so an unanswered blocked call will make the next request invalid. And practically, a model that receives a clear rejection reason ("refund exceeds $500 threshold, requires human approval") can react sensibly - telling the user it needs approval, routing to an escalation path - while a model that gets nothing back has no way to recover gracefully.
Post-execution checks still earn their keep - for a different job
Not every post-execution check is wasted effort just because it can't prevent the action it's checking. Two jobs suit it well. Normalisation: if different tools in a workflow return dates, statuses, or currency values in inconsistent formats, a post-execution step that rewrites every tool result into one consistent shape before the model reads it prevents a large class of misinterpretation errors - the model no longer has to guess whether "P" means "pending" or "processed," or whether a date is DD/MM or MM/DD. Audit and detection: logging every sensitive action, or flagging one for review after the fact, builds a record and a safety net for whatever gets past the pre-execution gates - useful, but a complement to prevention, not a substitute for it. The distinction to hold onto for the exam: normalisation and audit are legitimate post-execution jobs; preventing a non-compliant action from happening is not one of them, no matter how quickly the post-execution check fires.
Key concept
The decision framework is never about whether prompts are "good enough" in the abstract. It's about whether the consequence of a single failure justifies a deterministic guarantee - and once you've decided a gate is warranted, it must run before execution and must still return a tool_result on rejection so the model can react rather than the conversation breaking.