Guardrails belong at the action-decision layer, not the output filter
Production agent guardrails belong between a proposed action and its execution, not merely between generated text and the user. Output filters can catch unsafe language. They cannot reliably stop a polite sentence from accompanying a destructive database write, an excessive transfer, or an unauthorized message. The risk in an agent is the effect.
The action-decision layer has something a text filter lacks: structured facts. It can inspect the destination, method, parameters, credential, tenant, data classification, task context, current budget, and provenance of each argument before committing the call. Those attributes are where policy becomes enforceable. “Do not send sensitive information” is ambiguous prose; “deny external destinations when any argument derives from restricted records” is a runtime decision.
I want every consequential tool call converted into a typed proposal. Deterministic controls should run first: schema validation, destination allowlists, parameter ceilings, tenant boundaries, budget checks, and required approval state. Dynamic policy can then evaluate context that rules cannot express cheaply, while high-risk ambiguity routes to a human queue. The result is not only allow or deny. A good guardrail can re-ask for missing scope, fix a bounded formatting error, attenuate authority, substitute a read-only operation, or pause with an actionable explanation.
Placement makes the guardrail non-bypassable. If policy lives in the prompt, the model can misunderstand it. If it lives after tool execution, observability records an incident rather than preventing one. If each tool implements its own interpretation, controls drift across the fleet. A shared runtime control plane can apply one decision contract at the last responsible moment, while policy-as-code gives that contract versioning, review, tests, and rollout discipline.
This also improves evaluation. The system can measure denial reasons, false-positive rates, escalation latency, override frequency, and which proposed actions approach risk limits. Those traces reveal whether a control protects real boundaries or merely creates user friction. Guardrails are a product surface because operators and users need to understand what was blocked, what can be changed, and who owns the exception—not just receive a generic refusal.
Input and output controls still matter. Input validation reduces obvious injection and malformed requests; output filtering protects people from prohibited content and catches accidental disclosure in prose. They are guides around the loop, not the load-bearing effect boundary. Prompt injection becomes containable through permissions precisely because an injected plan still has to pass an independent action gate.
The gate must also bind its decision to the executed bytes. Approving a displayed summary and then letting the agent mutate arguments creates a time-of-check/time-of-use gap. The runtime should hash or otherwise identify the exact proposal, issue narrowly scoped credentials only after approval, and reject substitutions at dispatch. Evidence should join proposal, policy version, decision, approver, and observed result in one trace.
There is one precise concession: a model that only transforms text inside a sealed, read-only process can reasonably put most safety control at the input and output boundaries. If it has no tools, credentials, durable writes, or external communication, there may be no meaningful action layer to govern. The claim begins when generated intent can cross into an effectful system.
Tool schemas define the proposed action; policy decides whether that action is permitted now. I therefore design guardrails as a control plane over typed effects, with fast deterministic checks, explicit escalation, and evidence for every decision. Safe words are useful. Safe execution is the contract.