Do not write a separate ACL for your agent
Once an AI assistant can write data, the scary part is not a wrong answer from the model. It is a second permission layer quietly drifting away from the real one.
- Agentic AI
- Security
- Architecture
When you add an AI assistant to a product that already ships, the tempting move is to give it its own permission layer: a small config table listing which tool each role may call. It is quick to write and wrong for a long time.
The problem is not the model
The model can call the wrong tool — that is handled with tight schemas and an approval gate for side-effecting actions. The real risk sits elsewhere: you have just created two rule sets over the same data.
The first serves the UI and is validated every day by real users. The second serves the agent and only gets looked at during an incident. Months later a field becomes private in the first rule set, and nobody remembers the second one exists.
What I did instead
In the AI Connector assistant, every tool calls straight into the same permission and visibility layer the interface uses:
// The tool does not decide who may see what.
// It asks the same service the UI asks, as the user who is chatting.
const contacts = await contactService.search(query, { actor: session.user });
The consequence is easy to state, and easy to check:
When the permission layer changes, the agent inherits the change immediately — no separate migration, nothing for anyone to remember.
What it costs
This approach requires a server-callable permission layer that is decoupled from the HTTP tier. If your authorization logic is scattered across route handlers, you have to consolidate it first — which is work worth doing whether an agent shows up or not.
In exchange, the hardest question in shipping AI inside a product — "what is it allowed to read?" — becomes a question you already answered.