all posts
2026-02-17·4 min read·by Darko Gjorgjijoski·in AI

Capability scoping for agent tools

Handing an agent one broad tool and a polite note about what not to do is a deny-list, and it inherits every problem deny-lists have.

The fastest way to give an agent capability is to give it one broad tool. Run this SQL. Call this endpoint. Execute this shell command. One tool, unlimited reach, and the constraints expressed as instructions about what not to do.

The broad tool is quick to expose, but the difficult work remains: restricting what its credentials and implementation actually permit.

My position is that agent safety is mostly an API design problem, and that the prompt is the weakest available place to put a constraint. Not useless, but weakest. If a limit matters, it belongs in the shape of the tool, where the model’s cooperation is not required.

Allow-list, do not deny-list

A generic tool with instructions is a deny-list, and it inherits every problem deny-lists have ever had. You are enumerating the bad cases, and the set of bad cases is larger than your imagination.

Consider a tool that runs arbitrary SQL. Database permissions must enforce read-only access; a prompt is no substitute. Even with reads correctly enforced, unrestricted queries can expose other users’ data or exhaust resources through expensive joins.

Now consider seven narrow tools instead: list posts, get one post, create a draft, update a draft, import an image from a URL, set a draft’s featured image, and publish. This makes the intended operations explicit. Each still needs authorization, argument validation, resource limits, and tests; an image import, for example, must constrain the URLs it can fetch.

The trade is real. The narrow surface cannot do things you did not anticipate, which is frustrating the first time you want one of them. That inflexibility is the feature. A surface that can do things you did not anticipate is the definition of the problem.

Four rules that survive contact

No delete in this content workflow. Drafting and review do not need deletion, so I leave that operation outside the agent’s tools. Other workflows may need deletion, with recovery and authorization designed for that use case.

Mutation only on unpublished state. An agent that can edit drafts can be wrong in private. An agent that can edit live content is wrong in public, at whatever scale your audience happens to be. Reject the operation at the tool boundary based on the record’s state, not on whether the model believed it was editing a draft.

Make publication explicit. A separate publish operation requiring confirm=true avoids publishing as a side effect of editing. That flag is an API safeguard, not proof of human approval: a model can supply it. If human review is required, an approval mechanism outside the model must enforce it.

No generic escape hatch. Frameworks in this space often ship something like an execute-any-registered-capability tool, because it is genuinely useful during development. Shipping it defeats every other rule on this list in a single line, since the narrow tools become decoration around a general one. If a capability framework offers a default server exposing everything, turn it off and register only what you meant to expose.

Separate the principal, not just the tools

Narrow tools running as an administrator are narrow by convention only. If the underlying credential can do anything, then any bug in the tool layer, any path traversal in an argument, any unescaped identifier, restores the full surface.

The agent gets a dedicated role whose permissions match the allowed workflow. In this seven-tool example, that includes publishing through the explicit publish operation, while draft updates reject published records. Plugin installation, user management, and unrelated REST routes remain unavailable. A draft-only deployment should omit the publish tool and remove the credential’s publication permission as well.

This is also what makes the audit trail worth having. Actions arrive attributed to the agent’s own principal, so “what did the agent change last Tuesday” is a query rather than an investigation.

The test I would run before shipping any of it

Assume the model is fully compromised. Every instruction in its context is adversarial, and it will take the worst action available to it. Now enumerate what it can do.

If the answer includes publication, account for the possibility that the agent will publish. If the intended boundary is only creating and editing drafts for human review, enforce that narrower boundary in both the tools and credentials. Judge the design by the worst action actually available.

None of this is an argument for keeping agents away from real systems. I want them wired into real systems, because that is where they are useful. It is an argument that the interesting work is in the tool surface rather than the prompt, and that the tool surface is where I would spend the review time.

← older
Who is the agent acting for?
newer →
One public IPv4 for the whole cluster