Agentic AI systems violate the implicit assumptions of database design
TL;DR Highlight
Agents break DB assumptions, so soft deletes, idempotency keys and per-agent roles become essential
Who Should Read
Backend developers planning to give LLM agents Postgres access who need to design safety guardrails
Core Mechanics
- DBs assumed a human-written, deterministic caller
- Indexes and connection pools were tuned assuming a developer wrote, reviewed and deployed every SQL query.
- Agents reason their way to queries, so they may issue a never-seen five-table join.
- Agent writes may not be intentional
- Agents write on a wrong understanding, in loops, and on retries.
- In the article's example, an API returned HTTP 200 with an empty result and the agent approved 500 transactions on incomplete data.
- Add soft deletes, append-only logs and idempotency keys
- Tables agents write to get deleted_at, deleted_by and delete_reason instead of hard deletes.
- High-stakes data goes into an INSERT-only log table with a UNIQUE idempotency_key.
- Agents hold connections longer and multiply
- They hold a connection during LLM inference, and sub-agents fan out into parallel sessions.
- Use a dedicated agent pool and PgBouncer in transaction mode (the article's example: 20 real connections serving 500 clients).
- Bad queries fail silently
- An agent just uses a slow result and cannot tell an empty result from a wrong query.
- Tag queries with agent_id, task_id and step comments and aggregate them in pg_stat_statements.
- Schema is now a contract with the LLM
- Names like stat_cd and flg_1 lead Text-to-SQL to wrong queries.
- For legacy schemas, wrap them in an agent-facing VIEW with clear names and COMMENTs.
- Limit privileges with one role per agent type
- Give each agent its own role with GRANTs only on needed tables and columns.
- This shrinks the blast radius at the database level, not in app code.
Community Reactions
- Opinion: agents should not touch production DBs directly
- Several commenters said writes should go through stored procedures or an API layer with predefined allowed actions.
- They said exploratory queries belong on a separate analytics DB.
- Experience: a read/write split pattern in practice
- One commenter replicates OLTP to OLAP in near real time for reads and uses an API for writes.
- They use request_to_ban_user instead of ban_user so a human approves the action.
- Experience: read-only access was a big productivity win
- One commenter gave LLMs read-only DB access and said executives who wouldn't build reports now ask the agent.
- Technical pushback on the article's code
- A commenter noted a UNIQUE violation returns an error and is not silently ignored unless you use something like INSERT OR IGNORE.
- Another said Postgres connections are heavy, so the author probably meant sessions are brief.
- Opinion: humans already cause the same problems
- A commenter said with enough users, human-written queries are already unpredictable and inefficient.
- They recommended putting invariants and row-level permissions in the database.
How to Apply
- Give agents a role with timeouts first
- Today, create an agent_worker role with statement_timeout 5s and idle_in_transaction_session_timeout 10s.
- Switch the agent's connection account to this role to stop runaway queries.
- Add idempotency keys to agent write paths
- Hash task_id, operation and target_id into a key and store it in a UNIQUE column on the log table.
- Verify by inserting twice with the same key to confirm only one write lands.
- Wrap agent-visible schema in VIEWs
- Create agent_-prefixed VIEWs that rename legacy columns to meaningful names.
- Write COMMENTs like docstrings and grant agents access to views only.
- Tag queries with agent context comments
- Add a SQLAlchemy event hook that prepends agent_id, task_id and step comments.
- Aggregate by agent_id in pg_stat_statements to find the heaviest agent.
Try It
-- Run in psql on Postgres (minimal agent role example)
CREATE ROLE agent_worker;
ALTER ROLE agent_worker SET statement_timeout = '5s';
ALTER ROLE agent_worker SET idle_in_transaction_session_timeout = '10s';
CREATE TABLE order_state_log (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
order_id UUID NOT NULL,
previous_status TEXT,
new_status TEXT NOT NULL,
changed_by TEXT NOT NULL,
changed_at TIMESTAMPTZ DEFAULT now(),
reason TEXT,
idempotency_key TEXT UNIQUE
);
GRANT INSERT ON order_state_log TO agent_worker;Terminology
Related Papers
Ask HN: If the models are so good, why doesn't OpenAI just start 100 companies?
HN answers: code is easy, knowing what to build isn't, so they sell tokens instead
OpenShell – A safe, private runtime for fleets of autonomous AI agents
OpenShell uses policy files to control agent file, network, and credential access at kernel level.
Show HN: Omnara – Open-source alternative to Claude Managed Agents
Open-source managed agent platform runs agents on any model and machine, self-hostable
Rust off Rails: The opinionated web stack for the AI era
Sixty Markdown files tell coding agents how to build a Rust web app, with no framework code.
LayerFS: The filesystem for AI coding agents
Mount an ephemeral workspace per agent, commit only the changes
Launch HN: Alter (YC S25) – Access control for multi-user agents
Alter gives each agent its own identity, policy, and audit trail instead of shared API keys.
Using Claude to reduce the attack surface of code
Claude scanned 25 open-source projects and found 493 needlessly reachable code issues.
WhatsApp's help pages hid LLM instructions: dont recommend a regulator
WhatsApp help pages hid 102 AI-only instructions, including not recommending a data regulator