Skip to main content

Interdict: Runtime Safety for Agent-Written SQL

Status: Alpha PyPI Python CI Homepage Docs License


Install | Quickstart | How it works | Benchmarks | Configuration | Limits | Docs | Contributing | Security

Interdict is the safety layer between AI agents and Postgres. Agents can now issue real SQL against real databases; ordinary permissions answer "may this role touch this table?", but not "how much will this statement change?" or "can I undo it if the agent is wrong?" Interdict answers those questions before damage is done.

It parses SQL into a Postgres AST, applies deterministic policy, measures every write without executing it, holds high-impact changes for operator approval, and records supported writes so a human can approve reverting them. Blocks return structured explanations and repair hints so the agent can correct itself and retry.

Platforms. Interdict requires Python 3.11+ and a reachable Postgres database. The current public adapter is an MCP server; the safety engine is transport-agnostic.

Installation

pip install interdict-db

The PyPI distribution is named interdict-db; the command it installs is interdict. The separate interdict package on PyPI is an unrelated legacy dictionary utility.

Working on Interdict itself? Install the local development environment instead:

uv sync --group dev --python 3.11
docker compose up -d

See CONTRIBUTING.md for the full local validation loop.

Quickstart

The normal setup is three commands:

pip install interdict-db
interdict setup --name production
interdict connect claude --profile production

interdict setup is a guided terminal wizard. It tests the connection, discovers tables, creates a least-privilege policy, checks the database role, initializes the control store, stores credentials in the operating-system keychain when available, and creates a named profile. It never places a database URL or approval credential in the MCP configuration.

The connector configures the agent to launch Interdict automatically. You do not run a second server window. Verify the connection by asking Claude to call interdict_status, then ask it to work with the database normally.

Other supported clients use the same profile:

interdict connect codex --profile production
interdict connect cursor --profile production
interdict connect custom --profile production

For a safe read, Interdict checks the SQL and sends it to Postgres. For a dangerous or large write, Interdict measures the blast radius and holds the exact SQL for a human decision. Approvals happen in your terminal, never in the agent chat:

interdict approvals --profile production
interdict approve latest --profile production
interdict deny latest --profile production

Use the exact approval ID instead of latest when more than one request is pending. Holds expire after 30 minutes so a stale measurement cannot be acted on. A supported successful write returns an undo_id; a human can request the newest bounded revert with:

interdict revert latest --profile production

Interdict then tells the agent which approved tool call can complete the action. The approval credential never enters the model conversation.

Multiple databases

Configure each database once and select it explicitly:

interdict setup --name staging
interdict setup --name analytics
interdict profiles
interdict profile use production

The human chooses the active profile. Interdict does not expose an MCP tool that lets an agent switch itself to a different database.

No database handy for local evaluation? Start the seeded Pagila database and choose the Development preset in the wizard:

docker compose up -d postgres
interdict setup --name local-pagila

Production setup

Production mode refuses to connect an agent when the database boundary is unsafe. The application connection must be a non-owner, non-superuser role limited to the selected tables. Approvals, undo evidence, and the durable audit copy must use a separate database and role.

If the URL entered during interdict setup is too powerful, the wizard saves the profile as needs-dba, generates one owner-only SQL file for review, and stops. It does not grant itself privileges or connect the agent. A database administrator reviews and applies the script, then the customer reruns setup using the restricted role and checks it with:

interdict doctor --profile production
interdict connect claude --profile production

Advanced operators may still use environment variables and interdict init, but customers do not need to hand-write YAML or long MCP commands for the standard workflow.

For an upgrade from the older in-application adb_undo schema, run interdict migrate-control. It is idempotent and copy-only: it does not delete the old records. Verify the copy and your backups before manually revoking or archiving the legacy schema.

Benchmarks

Interdict keeps a hard latency budget: the pass-through path must stay under 5 ms added p99, and CI fails if the gate is exceeded.

What Result
Cost added per statement, warm path 2.6 us p50 / 2.7 us p99
End-to-end overhead vs raw asyncpg measurement-noise floor; CI gate requires added p99 < 5 ms
Dangerous statements missed, red corpus 0% of 40
Safe statements wrongly blocked, green corpus 0% of 18
Blast-radius measurement exact row counts, live
Undo round-trip ~4 ms, conflict-checked restore
Automated tests 378, run in CI on every commit

The benchmark methodology, caveats, and raw tables live in benchmarks/RESULTS.md. CI runs lint, the full pytest suite against seeded Postgres 16, and the latency gate on every push and pull request.

Configuration

Named profiles are the recommended configuration interface. The following variables remain available for advanced/manual deployments:

Variable Default Purpose
AGENT_DB_DSN local dev DSN Target Postgres connection string.
AGENT_CONTROL_DSN unset Separate control database for approvals, undo evidence, and durable audit events; required in production.
AGENT_SAFETY_PROFILE production production fails startup on unsafe privileges; development relaxes deployment topology.
AGENT_POLICY policies/default.yaml Database-agnostic safety policy.
AGENT_OPERATOR_TOKEN unset Required to approve held writes; use at least 32 random characters.
AGENT_OPERATOR_ID unset Stable identity recorded for the human operator; required in production.
AGENT_APPROVAL_TTL_SECONDS 1800 How long a held write stays approvable.
AGENT_AUDIT_LOG ~/.interdict/audit.jsonl Async audit log with raw SQL redacted and hashes retained.

policies/pagila.yaml shows a stricter allowlist-style policy for the bundled development database.

Honest limits

  • Interdict only governs SQL sent through its adapter. Do not give the agent a raw database DSN, cloud-admin token, shell with production credentials, or a second unguarded database tool.
  • Undo is bounded compensation, not a backup system. Interdict blocks automatic undo for unsupported statement shapes, user triggers, cascading foreign-key actions, oversized captures, and conflicts detected during restore.
  • Keep encrypted backups and point-in-time recovery in a different failure domain from the production volume, and regularly test restoration. A backup on the same volume does not protect against volume deletion.
  • Least privilege, dev/staging separation, reviewed migrations, CI/CD gates, provider deletion protection, and human incident procedures remain required.
  • The MCP adapter cannot intercept destructive cloud API calls such as deleting a Railway volume. The agent must not possess credentials scoped to those actions; enforce that boundary in your cloud IAM system.

Development

uv sync --group dev --python 3.11
docker compose up -d
uv run ruff check .
uv run black --check .
uv run pytest
uv run python -m benchmarks.ci_latency_gate

The seeded database mirrors the GitHub Actions service container: postgresql://postgres:postgres@localhost:5433/pagila.

Documentation

Repository Layout

engine/      safety core: parse, classify, policy, measure, undo, audit
adapters/    MCP server
policies/    YAML policies
corpus/      red and green query sets
benchmarks/  latency harness and CI gate
tests/       correctness, race, fault-injection, evasion, and MCP tests
examples/    local demo script
website/     landing page source for interdict.vercel.app
research/    study harness, figures, and paper artifacts

Contributing

Contributions are welcome for bug fixes, documentation, examples, tests, and tightly scoped improvements. Please read CONTRIBUTING.md before opening a pull request and follow the Code of Conduct.

Security

Please do not report security vulnerabilities through public issues or pull requests. Follow SECURITY.md for private reporting guidance.

License

Interdict is licensed under the MIT License.

Metadata

Release files for interdict-db 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for interdict-db 0.4.0
File Size Uploaded Provenance
interdict_db-0.4.0.tar.gz 91.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for interdict-db 0.4.0
File Interpreter ABI Platform
interdict_db-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 190.1 kB

Release files / interdict_db-0.4.0.tar.gz

Download URL interdict_db-0.4.0.tar.gz
Size 91.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6bccda005e9d9d4924735d84d23dbc9575f860c1131a81a0b7bbc1390db9fdf3
BLAKE2b-256 checksum
How to use checksums
5a58e1d2d9adea390d732d8518163542ca5c10cc91b43e3be4d342c8dc214745
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.22 {"installer":{"name":"uv","version":"0.11.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / interdict_db-0.4.0-py3-none-any.whl

Download URL interdict_db-0.4.0-py3-none-any.whl
Size 98.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
97cc3890e3c97bb4f8856a0332f8a8a7cd8566a51cd5b36d0f7ae4744b3ab8eb
BLAKE2b-256 checksum
How to use checksums
df7e42206b0470cf180406b2c096ac14f69fd16eb1fbe19df07af14bf2ee1c9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.22 {"installer":{"name":"uv","version":"0.11.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for interdict-db 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page