# SDK-Level Policy Enforcement Actually Matters for AI Agents

Most discussions about AI agent safety focus on the model. "Will it follow instructions?" "Can we prompt it not to do bad things?" "What if it gets jailbroken?"

These questions are important. They are also incomplete.

Even a perfectly obedient model is only as safe as the environment and tools you give it. If the agent can call any tool it wants whenever it wants, then a single successful injection or confused deputy situation is enough to cause real damage.

## Enforcement has to happen somewhere real

There are roughly three places you can try to enforce what an agent is allowed to do:

1. In the prompt / system instructions
2. In a wrapper or proxy layer around tool calls
3. At the point where the tool is actually invoked (inside the SDK or runtime the agent uses)

Most current agent frameworks rely heavily on 1 and 2. Number 3 is where things get interesting.

When policy lives only in prompts, it is subject to every prompt injection technique we already know about. When it lives in a wrapper, there is a constant arms race between the wrapper authors and people finding ways around it (indirect prompt injection through tool outputs, encoding tricks, etc.).

When the actual SDK that the model is using to call tools has a hook that runs before the tool executes, you have a much stronger position. The hook can see the intended action in its native form and apply rules that cannot be bypassed by clever text in the conversation.

## PreToolUse as a real control point

The Anthropic Claude Agent SDK (and similar designs) exposes hooks like `PreToolUse`. Before a tool is actually executed, your code gets to inspect the call and decide whether to allow it, modify it, or block it.

This is different from "the model promised it would only use these tools." This is the runtime saying "I will not let this action happen unless it passes these checks."

You can implement rules like:

- Only allow `shell` commands from an explicit allow-list for this agent
- Block any write operation to paths outside the declared working directory
- Require human approval (via the control interface) for certain high-impact actions
- Log every tool invocation with full context for audit

These checks run regardless of what the model says in its reasoning trace.

## The recipe should declare the policy, not just the tools

A common pattern is to say "this agent has access to GitHub and shell." That is too coarse.

A better declaration is closer to:

- Allowed tools: shell, git (with restrictions), vercel
- Shell is limited to: git, npm, node, vercel
- File writes are only permitted under ./work/
- Network access is whatever the container allows

When this lives in the recipe rather than in scattered code or prompts, it becomes reviewable and versioned. Changing the agent's power requires changing a file that goes through normal review processes.

## Why this is different from "guardrails"

Guardrails are often added as an afterthought. They try to detect bad behavior after the model has decided what it wants to do.

SDK-level enforcement (with policy declared in the recipe) is different. It changes what actions are even *possible* for that particular agent instance.

A researcher agent that has `publish: false` and no write access to repos physically cannot ship code, even if a prompt injection makes it want to. The boundary is not in the conversation. It is in the environment the agent was given.

## Practical consequences

Teams that take this seriously tend to:

- Create many narrow agents instead of one powerful general agent
- Treat recipe changes as security-relevant reviews
- Get comfortable giving agents more real capability because the scope is explicitly limited
- Have much clearer answers during security reviews ("this agent was only ever given these three secrets and these tool restrictions")

The alternative is hoping the model stays well-behaved while holding the keys to your systems.

## The model is not the only thing that needs to be constrained

A sophisticated model combined with broad, unaudited tool access is still a sophisticated way to shoot yourself in the foot.

SDK-level hooks + explicit per-mission policy + infrastructure isolation give you three independent layers. You do not have to trust any single one of them completely.

That is the difference between "we have an agent with some safety prompts" and "we have a system where the blast radius of a compromised agent is bounded by design."