When I give tools to an agent, I treat it like a third-party dependency: I don't trust it, I contain it.
The rule that matters: the constraint is set when the process starts, not in the prompt. A prompt is a request. The model can ignore it, or be turned around by malicious text slipped into what it reads.
On an agent I built, the tool list is closed in advance: twelve read tools allowed, fifteen write tools refused. It can't write a file or send a message, even if it tries.
Three more protections:
- an anti-injection section in the prompt, because an agent reads text it doesn't control,
- a mandatory adversarial pass before every output,
- human validation before anything is published.
Why this instead of "a good prompt": an agent that can act does what its environment allows, not what it was politely asked. If the action is impossible, there's nothing left to trust.
I care less about the speed these tools bring than about how to contain them: that's what lets you move fast without pulling code into a repo that nobody has read.
Amine Affif, full-stack developer in Paris. amineaffif.com
Top comments (2)
Fully agree on setting it at process start. The one gap I'd watch is the read side. With only read tools an injection can't write anything, but it can still steer what the agent says in its output, and that output is exactly what lands in front of the human for validation.
Does the adversarial pass run with the same context the agent read, or a clean one?
Putting the gate in the runner instead of the prompt is the only reliable wall. Once an agent reads untrusted text, system prompt instructions degrade under conflicting input.The read side still needs boundaries though. If an agent can read an arbitrary local file or external response, poisoned inputs can guide it to leak sensitive tokens into its allowed summary output.