Lesson 1.4
Workflow Enforcement, Guardrails and Handoff
Why prompts are suggestions and hooks are rules, and how to design guardrails and clean hand-offs in agentic systems.
A system prompt that says "never delete production data" is a request. A hook that exits with code 2 whenever a tool call matches rm -rf is a rule. The architect's job is to know which behaviours must be rules, and to implement them in the layer that cannot be talked out of them. This lesson covers the enforcement layers available around Claude, the guardrails they support, and how to hand work between agents and humans without losing state.
Probabilistic versus deterministic control
| Layer | Example | Guarantee |
|---|---|---|
| Prompt instruction | "Ask before pushing to main" | Usually followed; not guaranteed |
| Tool schema | strict: true, enum of allowed values | Input shape is guaranteed valid |
| Permission rules | deny: ["Bash(git push:*)"] | Tool call is blocked before execution |
| Hooks | PreToolUse script that rejects a command | Arbitrary code runs before or after the model acts |
| Programmatic gates | canUseTool callback, maxTurns, budgets | Your code decides; the model cannot override |
| Sandboxing | Container, restricted filesystem, no network | Damage is contained even if everything else fails |
Design from the bottom up. Decide first what the sandbox must contain, then which tool calls must always be denied, then which need a human, and only then what the prompt should encourage. Prompts shape behaviour; the lower layers bound it.
Guardrails that block
In Claude Code and the Agent SDK, a PreToolUse hook receives the proposed tool call as JSON on stdin and can stop it:
#!/bin/bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -qE 'rm -rf|DROP TABLE'; then
echo "Blocked: destructive command" >&2
exit 2 # exit 2 = block, stderr goes back to Claude
fi
exit 0
Exit code 2 blocks the action and feeds the message back to the model so it can choose a different approach. A hook can also return JSON with permissionDecision set to allow, deny or ask, which is the structured way to express the same thing and to route a call to a human.
At the API level the equivalents are schema validation on tool_use.input before execution, an allowlist of permitted operations inside each tool implementation, and refusing to execute anything whose arguments fail validation (send back is_error: true instead).
Guardrails that pause
Human-in-the-loop is a guardrail with a person in it. The mechanisms are the ask permission decision in hooks, the permissions.ask rule list in settings, the Agent SDK canUseTool callback (which can await a UI prompt before returning), and tool-runner per-turn hooks for a manual loop. Reserve human gates for actions that are irreversible or externally visible: sending messages, spending money, deleting data, deploying. Everything else should be either automatically allowed or automatically denied; a flood of approval prompts trains people to click through.
Guardrails that bound
Iteration limits (maxTurns), per-session cost caps, wall-clock timeouts and task budgets stop runaway loops. A Stop hook can also enforce completion criteria: if the agent tries to finish without running the test suite, the hook can return decision: "block" with a reason, and the agent continues. Use this sparingly and always with an escape condition, or you create a loop that cannot end.
Handoff between agents
A handoff is a transfer of responsibility from one agent to another, typically from a generalist orchestrator to a specialist. Clean handoffs share three properties:
- An explicit payload. The receiving agent gets a brief that states the goal, the constraints, what has been done and what remains. Structured output (JSON with a schema) makes the payload machine-checkable.
- Externalised state. Anything the next agent needs to continue (files changed, decisions taken, open questions) is written to disk or a store, not left in the sender's context, which the receiver cannot see.
- A return contract. The receiver knows what to report back and in what form, so the sender can verify rather than trust.
Handoff to a human follows the same shape: a summary of state, the specific decision required, and the options. Escalation that dumps a raw transcript on a person is not a handoff.
Putting it together
A typical layered design for a deployment agent: the container has no credentials beyond a scoped deploy token (sandbox); permissions.deny blocks all git push to protected branches (rule); a PreToolUse hook requires approval for any command containing deploy (human gate); maxTurns is set (bound); and the system prompt explains the release process (guidance). Remove any one layer and the others still hold.
Exam focus
- Prompts are probabilistic; hooks, permission rules, schemas and sandboxes are deterministic. Safety-critical constraints belong in deterministic layers.
- A
PreToolUsehook blocks with exit code 2 (stderr returned to the model) or with JSONpermissionDecision: "deny". - Human approval gates should be reserved for irreversible or externally visible actions to avoid approval fatigue.
Stophooks can refuse to let an agent finish, but need an escape condition.- A clean handoff has an explicit payload, externalised state and a return contract; the receiver never sees the sender's context.
- Layer defences so that each one holds independently of the others.
Check yourself
5 questions
1.A team wrote 'Never run database migrations against production' in CLAUDE.md, yet Claude ran one during a session. What is the correct architectural understanding?
2.Which Agent SDK mechanism is designed to obtain a human decision before a specific tool call executes, when no earlier rule has already allowed or denied it?
3.An agent has a general bash tool and has been observed sending emails with curl. The architect wants every outbound email gated behind human approval and recorded in an audit log. Which design is most robust?
4.In a routing workflow a triage agent hands a customer case to a specialist agent. Which handoff practice best preserves reliability?
5.A team runs an Agent SDK application in bypassPermissions mode inside an isolated container, but still wants certain tools blocked absolutely. Which control still applies in that mode?
