← Blog3 min read

Human-in-the-Loop Approvals for Agent Writes and DDL

Read-only by default is the right starting point, but it is binary: the agent can write, or it cannot. There is a middle ground that comes up constantly once you let agents do real work. The agent should be able to write, but only with a human looking at the specific statement first.

A backfill that updates a million rows. A schema change generated by a coding agent. A DELETE that cleans up stale records. These are exactly the actions where you want the agent's speed and a human's judgment on the same statement, before it runs.

How approvals work

When a credential is configured for approvals, PgBeam holds matching statements in a queue instead of running them. The write or DDL does not reach the database. A human sees it in the dashboard: the exact SQL, which credential issued it, and the context around it. They approve or reject. On approval, the statement runs. On rejection, it does not, and the agent gets an error it can read.

The agent does not have to be rewritten to support this. From its side, a held statement is just one that has not returned yet, or one that was refused. The hold, the review, and the decision happen at the wire and in the dashboard, not in the agent's code.

Auto-approve the safe cases

A queue that holds everything is a queue nobody empties. The point is to hold the consequential statements and let the routine ones through. Auto-approve rules do that: define the cases that are obviously safe and let them run without a human, so the queue only ever contains the statements that actually warrant a look.

The shape of those rules is up to you: an UPDATE that touches a single row by primary key might auto-approve, while one with no WHERE clause always waits. An INSERT into a staging table might auto-approve, while any DDL always waits. The principle is to spend human attention on the statements where it changes the outcome.

Auto-expire the queue

A held statement should not wait forever. An approval request that nobody acts on within a window auto-expires and is rejected. This keeps the agent from blocking indefinitely on a human who stepped away, and it keeps stale, half-considered writes from running hours later when the context that produced them is gone. If it mattered, someone approves it in time. If it expires, the agent can resubmit with fresh context.

The agent angle and the human angle

For agents, approvals are the bridge between "read-only, totally safe, somewhat limited" and "full write access, useful, scary." You get an agent that can propose consequential changes and execute them, with a checkpoint exactly where the risk is. A coding agent can author and run a migration, and you see the DDL before it locks a table.

For humans, the same queue is a review step for sensitive operations regardless of who initiated them. A contractor's destructive statement waits for a senior engineer. An on-call action against production gets a second pair of eyes. The approval is about the statement, not about whether the principal is silicon or carbon.

Where it sits

Approvals compose with the rest of the policy. The held statement is still subject to allowlists, row-level policies, and budgets, and every approval and rejection lands in the audit log with the decision and the approver. When you need the change to happen somewhere even safer than approved-production, route it to an instant branch instead.

The result is a workflow where an agent can do consequential work, and a human is in the loop precisely when, and only when, it counts.

Try PgBeam or see the full feature set.

Give your agent Postgres it can't wreck

Issue a scoped credential, attach a policy, and watch every query in the audit log. No credit card required. 14-day free trial.