Skip to main content
A prompt that says “only run SELECT” is a suggestion. A connection that cannot write is a guarantee. A production data agent answers from a read-only connection and isolates any writes to a schema it owns. The boundary holds even when the model goes off-script.
Create the readonly role without write grants before using this connection. The default_transaction_read_only=on setting blocks ordinary write statements, but it is a configurable session default. Database ownership and grants remain the security boundary.

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. The Engineer’s writes are scoped to a schema (for example dash) that the Analyst never touches. The database rejects DROP TABLE public.users because the Engineer’s role has no write grant on public.

Gate the writes that remain

For writes you do allow, add a human in the loop. requires_confirmation produces a paused run that the client must continue with an approval before the function executes.
For a dedicated writer built on SQLTools, set requires_confirmation_tools=["run_sql_query"]. That pauses every call to the tool, reads included, so a narrow custom write tool gives finer control. Gate the irreversible actions and leave reads ungated, so approval fatigue does not set in.

Layers of defense

Next steps

Developer Resources