Destructive SQL never runs.

An ordered deny list, checked against every statement your agent sends. DROP TABLE, DELETE without a WHERE, TRUNCATE: the sidecar refuses them before your database sees them.

Alerts come after the damage.

Monitoring tells you a table was dropped. It tells you after, at 3:12 AM, once the rows are gone.

An agent does not wait for that window to close. It issues the next statement in milliseconds, then the one after.

A human incident response
  • 2:47 AMAlert fires
  • 3:12 AMOn-call sees alert
  • 3:45 AMEscalation
  • 4:15 AMAccess revoked

88 minutes to revoke access.

You write what is forbidden.

A guardrail is a rule in your config file. The sidecar checks every statement against the list before passing it upstream. A statement that matches never reaches your database.

  1. An ordered list

    Rules run in the order you wrote them, against every statement. The first match decides. No scoring, no ambiguity, same answer every time.

  2. Operations, not string matching

    A rule names the operations it refuses: drop, delete, truncate. It reads the parsed statement, so it catches a variant a regex would miss.

  3. Your message, on the wire

    You write the refusal text. The client receives it as a real protocol error, not a dropped connection.

  4. Named rules

    Every rule carries a name, and the name travels with the refusal. The log and the client cite the same rule.

Nothing reaches the database.

Pick a statement your agent sends and read what comes back on the wire.

Parsed as drop, listed as drop. The first match decides.

policy.rules
  - name: no-destructive-sql
    type: operation
    operations: [drop, delete, truncate]
    message: destructive statements are not permitted
agent-07 → prod-db:5432
● postgres(DROP TABLE customers)
  ⎿  FATAL:  destructive statements are not permitted
     hoop.dev · guardrail: no-destructive-sql

agent-07 reads the refusal. No retry, no stall.
> clean up the old test rows in customers

● postgres(DELETE FROM customers WHERE id = 1)
  ⎿  FATAL:  destructive statements are not permitted
     hoop.dev · guardrail: no-destructive-sql

Refused, and the agent kept going.

A blocked statement comes back as a real pgwire error carrying the message you wrote. The agent reads why the sidecar refused it instead of guessing at a dropped connection.

So it does not retry the same statement, and it does not stall. It finds a compliant path on its own.

Four controls, one sidecar.

One rule is enough to start.

Name the operations you never want an agent to run, write the message it should read instead, and start the sidecar. Free and open source under MIT.

Ask an assistant how Guardrails works: Claude, ChatGPT, Grok, Gemini, Perplexity, Copilot.

# config.yaml
policy:
  enforce: true
  rules:
    - name: no-destructive-sql
      type: operation
      operations: [drop, delete, truncate]
      message: destructive statements are not permitted

$ hoop start sidecar --config config.yaml
sidecar running