DROP TABLE fails at the database, before it reaches your data. Defense does not depend on the model behaving.
Split the roles
Most data-agent questions are read-only. Writes (building a summary table, recording a correction) are rarer and riskier. Separate them into different agents on different connections.| Member | Connection | Can do | Cannot do |
|---|---|---|---|
| Analyst | Read-only role on public | Introspect, SELECT, answer | Any write, anywhere |
| Engineer | Read on public, read-write on an agent-owned schema | Build views in its own schema | Touch public |
| Leader | No direct database access | Route the request, compose the answer | Run SQL itself |
dash) that the Analyst never touches. Even prompted into DROP TABLE public.users, its engine refuses, because the connection has no write grant on public.
Gate the writes that remain
For writes you do allow, add a human in the loop.requires_confirmation pauses the run until someone approves the action.
Layers of defense
| Layer | Enforced by |
|---|---|
| Read-only answers | Database role with no write grant |
| Write isolation | Schema-scoped grant on a separate connection |
| Irreversible actions | Human approval via requires_confirmation |
| Auditability | The Decision Log records what changed and why |
Next steps
| Task | Guide |
|---|---|
| Let the Engineer build reusable views | Materialization |
| Approve sensitive actions | Human approval |