squidbrake

Quickstart

Block your first dangerous tool call.

Install Squidbrake, connect the agents on your machine, and watch it stop a destructive command. About five minutes. Python 3.10 or newer.

01Install and connect

pipx install squidbrake      # or: pip install squidbrake
squidbrake connect all       # routes every agent on this computer through it
squidbrake                   # starts the gateway and opens the dashboard

connect all finds Claude Code, Codex, Gemini CLI and the other agents it supports, backs up every config it changes, and can be undone with squidbrake connect all --remove. Run squidbrake connect status to see which agents are covered. Restart your agents after connecting.

02Watch a call get blocked

Ask your agent to run rm -rf ~/. The call never reaches the shell. This is what Claude Code receives from the hook:

{"hookSpecificOutput": {
  "hookEventName": "PreToolUse",
  "permissionDecision": "deny",
  "permissionDecisionReason": "Squidbrake blocked this (rule 'block-destructive-shell'):
    Destructive shell command. Don't try to work around it."
}}

The same decision shows up in the dashboard with the full call, the rule that fired and the session it came from.

03Write your policy

Policy is one YAML file. Rules are read top to bottom and the first match wins. Each rule says allow, deny or review, which holds the call until a person approves it. Sequences look at what the agent did before.

rules.yaml
default: review
default_reason: Changes need a person to approve them

rules:
  - id: allow-reads
    action: allow
    match:
      name: ["Read", "Grep", "Glob"]

  - id: review-stripe-money-out
    action: review
    reason: Refunds and payouts require finance approval
    approvers: ["role:finance"]
    match:
      name: ["stripe.*refund*", "stripe.*payout*"]

sequences:
  - id: destroy-after-recovery-removed
    action: review
    reason: Destroying data right after its backups were turned off
    match:
      input_regex: 'delete[-_ ]?db[-_ ]?instance|drop\s+database'
    after:
      match:
        input_regex: 'backup[-_ ]?retention[-_ ]?period\W{0,4}0\b'
      within_hours: 24

The default rules.yaml also checks shell commands, prompt injection from fetched content, and history. Set mode: shadow to log what would be blocked without blocking anything.

04Use it from your own code

Anything that makes tool calls can ask the gateway first. Over HTTP:

curl -s localhost:8080/v1/events \
  -H "X-Gateway-Key: $SQUIDBRAKE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"tool","name":"Bash","input":{"command":"rm -rf ~/"},"session_id":"demo"}'

# response
{"event_id": "20afe04f-…", "decision": "deny",
 "reason": "Destructive shell command", "rule_id": "block-destructive-shell",
 "status": "denied"}

To put an MCP server behind Squidbrake, wrap it:

squidbrake proxy --app linear --url https://mcp.linear.app/mcp
squidbrake proxy --app stripe -- npx -y @stripe/mcp --tools=all

05Run it for your team

docker run -d -p 8080:8080 -v squidbrake-data:/app/data \
  --name squidbrake ghcr.io/batrapulkit/squidbrake
docker logs squidbrake       # prints the first API keys

Postgres, HTTPS with Caddy, Slack approvals and audit export are covered in the README.

Want help writing a policy for your agents? Book 30 minutes with us.