Adapters: make pg_policy work for every agent runtime

One SQL contract, many PEPs. The PEP is whatever actually invokes tools.

evaluate(principal_type, principal_id, action_type, action_id,
         resource_type, resource_id, context jsonb, session_id)
  → { decision, allowed, obligations, reasons, mode, matched_policies }

1. Raw SQL / any driver

SELECT pg_policy.evaluate(
  'agent',
  'langgraph:analytics',
  'tool',
  'execute_sql',
  'table', 'public.orders',
  jsonb_build_object(
    'statement_type', 'SELECT',
    'acting_for', 'user:42',
    'tenant_id', 'acme'
  ),
  'thread-abc'
);

Python: examples/integrations/evaluate_middleware.py


2. MCP Postgres servers

Wrap query / execute_sql / explain_query:

  1. Classify statement_type (SELECT/INSERT/…; fail closed on unknown).
  2. evaluate with action_id = MCP tool name.
  3. On deny: return MCP error with reasons (do not execute).
  4. On max_rows: inject LIMIT / truncate.
  5. On prefer_tool: include in error/hint so the model can call explain_query.

This replaces per-server hardcoded allowlists. Keep BEGIN READ ONLY as defense in depth.


3. LangGraph ToolNode

  • session_id = config["configurable"]["thread_id"]
  • principal_id = graph/agent name
  • Wrap each DB tool with the middleware before the SQL runs
  • Persist checkpoints with PostgresSaver and policy in the same cluster when possible

Human-in-the-loop: map interrupt() to a guide/forbid that requires context.approved == "true" after the human resumes.


4. CrewAI / AutoGen / Letta

Assign one principal_id per role (crew:researcher, crew:writer). Load examples/packs/multi-agent.sql. The crew process is not a security boundary; pg_policy is.


5. Cursor / Claude Desktop / IDE MCP

Prod connections: devops.sql + read-only role + enforce.
Personal dev: log_only is acceptable; still load baseline so you see shadow_denies.


6. HTTP / AuthZEN PEP

Map:

AuthZEN pg_policy
subject.type/id principal_*
action.name action_id (action_type=tool)
resource.type/id resource_*
context context jsonb
decision boolean allowed

Obligations travel in your PEP’s extra context until the HTTP sidecar exists (roadmap 0.3).


7. What if the host forbids CREATE EXTENSION?

Until Neon/RDS allowlist you:

  • Run pg_policy on a policy sidecar Postgres (evaluate remotely), or
  • Load the SQL as a plain schema in a self-hosted replica used as PDP, or
  • Use the same APL files in CI against a local PG.

The language and packs stay identical. The extension is the preferred PDP, not the only place APL can be stored during transition.