Why databases must govern agents (and how pg_policy does it)

Audience: database engineers, platform teams, agent-framework authors, security/compliance
Last updated: 2026-08-10
Status: public thesis


1. The shift nobody budgeted for

For thirty years, PostgreSQL assumed a human-shaped client: a role, a session, a few statements per second, intent that is mostly honest.

Agentic systems invert that:

Human client Agent client
One user, one app One user → many agents → many tools
SQL written by a developer SQL invented at runtime
Predictable statement mix Tool storms, retries, fan-out
IAM + RLS is enough IAM + RLS is necessary and not sufficient
Audit “who logged in” Audit “which model, which tool, on whose behalf, after which prior acts”

The industry already moved retrieval (RAG) behind metadata filters. Tool-using agents expand the governance surface: schema discovery, SQL construction, writes, exports, sibling agents, MCP brokers. AWS’s 2026 data-mesh guidance says it plainly: RAG needed one checkpoint; agents need a checkpoint at every data interaction.

Postgres is where those interactions become real. If policy does not live beside the data, every LangGraph graph, CrewAI crew, Cursor MCP, and homegrown SQL tool will reimplement a worse, drifting copy of the same rules.

That is the value of pg_policy.


2. The three-plane model

┌─────────────────────────────────────────────────────────────┐
│  Plane C — Model / content                                  │
│  Prompt injection filters, topic allowlists, PII redaction  │
│  (Bedrock Guardrails, NeMo, Llama Guard, …)                 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  Plane B — Agent / tool control   ← pg_policy lives here    │
│  May this agent call this tool, with this context,          │
│  given this session history? Hard deny + soft guidance.     │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  Plane A — Data isolation       ← Postgres RLS / GRANT      │
│  Which rows/columns exist for this tenant/user?             │
└─────────────────────────────────────────────────────────────┘

Most teams only build A (RLS) or only C (LLM firewalls). B is the missing plane. Without it:

  • A read-only role still lets an agent COPY 40 million rows into a prompt.
  • RLS still lets an agent call export_csv 200 times an hour.
  • An MCP server that regex-blocks DROP still loses to COMMIT; DROP… (the deprecated reference Postgres MCP taught this the hard way).
  • Multi-agent crews share one service account; nobody can answer “which agent did this?”

pg_policy is plane B inside PostgreSQL, so A and B share transactions, catalogs, and audit.


3. What the research shows (2025–2026)

3.1 Relevance is not authorization

Enterprise RAG ranks by similarity, not permission. The 2026 work Securing the Agent (ACM) shows tool-mediated disclosure, context accumulation, and client-side orchestration bypass. Server-side ABAC at tool time eliminated cross-tenant leakage (~19 ms). That is the same job evaluate() does for SQL/MCP tools.

3.2 MCP servers are reinventing policy in process memory

Safe Postgres MCP implementations (safe-postgres-mcp, pgguard-mcp, Crystal DBA postgres-mcp) all independently add:

  • read-only transactions
  • statement timeouts
  • row caps
  • AST / single-statement checks
  • denial audit logs

Those are policy. They should not be unique snowflakes per MCP binary. They should be data next to RLS, versioned in Git, evaluated in SQL.

3.3 Frameworks persist in Postgres but do not govern through it

LangGraph’s production pattern is PostgresSaver for graph checkpoints. CrewAI, AutoGen/AG2, Letta all speak MCP. The state store is Postgres; the policy store is not. That split is accidental, not architectural.

3.4 Regulation now expects an agent control plane

EU AI Act Article 12 (high-risk logging; widely cited full-enforcement milestone August 2026), GDPR accountability, HIPAA unique-user identification, SOC 2 monitoring, ISO/IEC 42001: logs must be structured, attributed (human + agent), correlated by session, and not “the LLM’s service account did something.” pg_policy.decision_log + sessions + events are the database-shaped answer.


4. Value, stated as jobs-to-be-done

Who Job How pg_policy helps
DBA / platform Stop agents from DDL, COPY, superuser paths forbid packs + least-privilege recipes
App security One policy for every MCP/gateway evaluate() as PDP; AuthZEN-shaped JSON
Agent engineer Steer, don’t only block guide obligations: max_rows, prefer_tool, advice
Compliance Reconstruct a session decision_log + temporal events
Multi-tenant SaaS Tenant isolation and tool isolation RLS (A) + APL (B)
Framework author Don’t ship another regex firewall Call SQL; inherit DB policy

5. What “works for all” means

Not one mega-policy. A universal kernel plus packs:

  1. KernelCREATE EXTENSION, evaluate, modes log_onlyguideenforce
  2. Identity conventionprincipal_type=agent, id = framework agent name; context.acting_for = human user
  3. Tool vocabulary — stable action ids (execute_sql, explain_query, export_csv, list_tables, …)
  4. Packs — domain SQL you load in minutes (analytics, support, fintech, healthcare, devops, multi-agent)
  5. Adapters — 15-line middleware for MCP / LangGraph / any HTTP PEP

If your agent can run SQL, it can call pg_policy.evaluate. That is the compatibility story: SQL is the lingua franca, not another SDK.


6. Honest limits (trust is earned)

  • APL v0.1 is a small total language, not Cedar’s SMT analyzer.
  • Superusers and BYPASSRLS still bypass data-plane controls (Postgres fact).
  • Default mode is log_only so you cannot surprise-deny production.
  • This does not replace GRANT, RLS, network policy, or model guardrails.
  • Managed clouds must allowlist the extension before CREATE EXTENSION works there.

Those limits are why we ship shadow mode, packs, and RLS complements instead of claiming a silver bullet.


7. Call to the database community

Postgres already won vectors, JSON, RLS, and (increasingly) agent state. The next primitive is agent policy. If we do not define it in-tree-as-extension, it will be defined in fifty incompatible MCP servers and three cloud consoles.

pg_policy is that primitive: readable policy, session memory, guidance, audit — next to the rows agents actually touch.

Read next: use cases · onboarding · what to add next · policy packs