Squidbrake
Change control for AI agents. Agents propose. People approve.
Your AI agents run commands, edit code, call MCP tools, send emails, issue refunds and change databases. Squidbrake sits between the agents and those actions:
- routine work runs on its own, and is recorded
- risky changes wait for a person who isn't the one who asked
- catastrophic ones are blocked
Every decision goes into a tamper-evident record that someone outside engineering can read.
One policy covers every agent your company runs: Claude Code, Cursor, Codex, Gemini CLI, VS Code Copilot, Antigravity, and any MCP tool. Free and open source (Apache 2.0). Runs on your laptop or your own server.
Why
Agents are good at each step and blind to the whole. Often every step is allowed, and the combination isn't:
- An agent turns off a database's backups. Later, in another conversation or from another agent, it deletes the database.
- An agent reads a web page, an issue or a support ticket that names an address. It then sends your data there.
- A person rejects a force push, and the agent retries it with a different spelling.
Built-in agent permissions judge one tool call at a time, inside one agent. Squidbrake judges each action against what came before it, across conversations and agents. A person signs off on what matters, with the reason and the steps that led to it.
How it works
agent (Claude Code, Cursor, Codex, MCP client, your own code)
│ every action, before it runs (hook, MCP proxy or HTTP)
▼
Squidbrake gateway ── rules.yaml + what came before ──► allow · hold for a person · block
│ │
└──────────── tamper-evident record ◄──────────────────────┘
dashboard · phone · Slack · Teams · email · SIEM
- Deterministic. No LLM decides anything. Rules and checks are in
rules.yaml, hot-reloaded on save. - Reads what a command really does before it runs:
ls && rm -rf ~/,bash -c "...",curl ... | sh- Makefile targets and
package.jsonscripts - commands sent over
ssh,docker execandkubectl exec
- Shows the approver the blast radius, measured on the developer's machine:
- "removes 3 commits from origin/main"
- "deletes 4,312 rows of 10,240 in orders"
- "destroys 12 resources, including aws_db_instance.main"
An agent read an "urgent CEO" email from acrne-corp.com and tried to wire $24,800. Blocked, with the story of what led to it. |
Approve or reject from your phone with one tap. |
Quick start
1. Install. One line installs it, runs it in the background, connects every agent on this computer, and opens the dashboard:
curl -fsSL https://pilots.squidbrake.com/install.sh | SQUIDBRAKE_REF=github sh # macOS / Linux
$env:SQUIDBRAKE_REF="github"; irm https://pilots.squidbrake.com/install.ps1 | iex # Windows
Or with pip: pip install squidbrake && squidbrake setup.
2. Start in observe mode. Nothing is blocked or held; Squidbrake records what it would have done:
squidbrake connect all --mode observe
squidbrake doctor # every agent connected, and what each one's hook does and doesn't check
3. Review after a week:
squidbrake report --week # held, blocked, would-have, false-positive rate, decision time, chains caught
Mark any hold that shouldn't have happened with "This was legit" in the dashboard, or
squidbrake feedback EVENT_ID legit. The report counts the false-positive rate per rule.
4. Enforce. Set mode: enforce in ~/.squidbrake/rules.yaml. You can also enforce rule by rule (mode: on a
single rule) and observe the rest.
Even in observe mode, three things are always enforced:
- catastrophic commands (
rm -rf ~/, wiping a drive) - an emergency stop
- an agent reaching for Squidbrake's own approval path
No install? Open the live demo in your browser: a sandbox company's support agent works its inbox while you watch.
More ways to install: docs/install.md. First run not right? docs/troubleshooting.md.
What it controls
| Control | What it does | Details |
|---|---|---|
| Sign-off by a second person | Risky changes wait in the dashboard, on a phone (one tap, optional Face ID / fingerprint), or in Slack, Teams or email. A key can't approve its own request, and per rule (second_person: true) or for the team, nobody approves what their own agent asked for. Roles: only finance approves wires |
rules |
| Command checks | Catastrophic commands are blocked. Irreversible ones (git push --force, terraform destroy, kubectl delete, cloud deletes, DROP TABLE) and code that can't be read (python -c, curl | sh, a script the agent just wrote) wait for a person. Commands that only look run |
rules |
| Chains | An action is judged by what came before it: backups off and then a delete, a retry after a no, a refund loop. This works across conversations and agents, until the earlier step expires (squidbrake capabilities) |
rules |
| Prompt injection, without a model | Sending to an address that only outside content mentioned (a web page, an email, an issue), even in an earlier conversation, waits for a person. The approver is told where the address came from | rules |
| Data in public places | A customer's name or personal data in a PR, issue, comment or chat post waits for a person | rules |
| Undo | Before an approved delete, git reset --hard or git clean, a copy is kept. squidbrake undo puts it back |
rules |
| Self-protection | An agent can't approve its own action, read Squidbrake's keys, or switch Squidbrake off without a person. Every minute it checks that its hooks, rules and installed files are unchanged | threat model |
| Evidence | A hash-chained record with signed checkpoints that anyone can verify offline (python verify.py, squidbrake audit verify). A Monday summary, and an evidence pack for auditors (squidbrake evidence) |
operations |
| Spend limits and kill switch | Pause an agent after N tokens or dollars a day. Stop one agent, one conversation, or all of them, from the dashboard or a phone | rules |
An example from the shipped rules.yaml:
rules:
- id: approve-money-out
action: review # allow | review (a person decides) | deny
reason: Bank transfers, wires and payouts need finance sign-off
timeout_seconds: 900
approvers: ["role:finance", "role:admin"]
match:
name: ["*transfer*", "*wire*", "*payout*"]
sequences:
- id: runaway-refunds
action: deny
reason: Too many refunds in a short time; the agent may be stuck in a loop
match: { name: ["*refund*"] }
count: { more_than: 10, within_hours: 1, scope: identity } # across all of one person's agents
Proof
The incidents and the session benchmark run in CI, so they can't quietly stop being true.
- Real incidents: incidents/ replays 11 public AI-agent incidents against the shipped rules.
- Examples: Replit's production database, the Railway volume deletion, GitHub MCP, Supabase MCP, CurXecute.
- 13 of 14 harmful actions are stopped.
- Reported bypasses: every way around Squidbrake that someone sent us is a test that must stay stopped on
every release (tests/test_reported_bypasses.py): 16 of 16 stopped, and
the everyday variants of each still run.
- The one not stopped is listed and explained: a malicious MCP server adds a BCC inside itself, after the check.
- Whole sessions: in bench/chains/, Squidbrake stops 64 of 65 harmful steps and holds 3 of 41 routine ones. An allowlist stops 53 and holds 10.
- Other tools: bench/compare/ runs the same steps through two other tools (dcg and Microsoft's Agent Governance Toolkit), plus everyday coding work. This one is run by hand, not in CI.
- Claims audit: AUDIT.md checks every claim on this page against the code. Gaps still open are tests that fail on purpose.
Supported agents
| Agent | What's checked |
|---|---|
| Claude Code | every tool call: commands, edits, reads, web, MCP (hook, or the Claude Code plugin) |
| Cursor | terminal commands, file reads, edits and deletes, MCP tools |
| Codex | shell commands, edits, MCP tools. Approve the hook once in Codex with /hooks |
| Gemini CLI | shell commands, reads, writes and edits, and its MCP servers |
| VS Code Copilot | agent-mode commands, reads and edits, and its MCP servers |
| Antigravity | terminal commands, reads and writes, and its MCP servers |
| Windsurf, Kiro, Claude Desktop | their MCP servers |
| Any MCP client, ChatGPT / claude.ai connectors, Devin, n8n | through the MCP proxy, by command or by URL |
| Your own agents (OpenAI Agents SDK, LangGraph, CrewAI, ...) | gw.guard_tools(tools) in Python, or two HTTP calls from any language |
squidbrake doctor lists, for each agent on a computer, what its hook doesn't see.
Details: docs/install.md and docs/integrations.md.
Deployment
- One laptop: the quick start above. Data, keys and rules stay in
~/.squidbrake. - A team:
- Run one gateway on a server:
./install.sh gateway.yourcompany.comfrom a clone sets it up with HTTPS. Or use Docker:docker run -d -p 8080:8080 -v squidbrake-data:/app/data ghcr.io/batrapulkit/squidbrake. - Connect each laptop with
squidbrake connect all --url https://gateway.yourcompany.com --key gw_.... Each agent key works for one person. - For several replicas, use Postgres (
DATABASE_URL).
- Run one gateway on a server:
- Company-wide:
squidbrake lockdown --url https://gateway.yourcompany.comwrites the managed-settings files IT pushes to every machine. Each agent must then run Squidbrake's hook, and--dangerously-skip-permissions/--yoloare turned off. - Integrations: Slack (approve and reject in the channel), Microsoft Teams, email, phone push (ntfy), and SIEM export (Splunk HEC, Datadog, any HTTP endpoint).
Security model and limits
Squidbrake is a policy and approval layer for agents that make mistakes or follow instructions they shouldn't. It is not a sandbox against an agent deliberately trying to escape.
- It doesn't see code running inside an allowed program or an MCP server, a background process started earlier, a tool that isn't connected, or someone with admin rights on the machine.
- It doesn't make an over-privileged agent safe. Use it with least-privilege credentials, and a container or VM for untrusted work.
- While the gateway is down (
when_unreachable: block_risky, the default):- what the rules already allow (reads, everyday coding work) still runs, unrecorded
- anything that would wait for a person, and any command that can't be undone or can't be read, is blocked
- AWS IAM reach isn't checked yet. An agent giving itself admin in small steps isn't caught. This is on the roadmap and is an open test in AUDIT.md.
- The evidence pack shows which controls exist for SOC 2, ISO/IEC 42001, the EU AI Act, CERT-In and RBI. It doesn't make you compliant.
The full list, per agent and with the test behind each claim, is in THREAT_MODEL.md. To report a vulnerability, see SECURITY.md.
Privacy
What your agents do never leaves your machine or server: commands, files, prompts, tool inputs and outputs, and the audit trail.
Anonymous usage counts are sent to the Squidbrake team:
- the command name and version
- how many actions were allowed, held and blocked
- the decision time
- for each hold or block, only the program (like
rm) and the rule
The first run in a terminal says so. squidbrake telemetry status shows exactly what is sent, and DO_NOT_TRACK=1
turns it off. Details: docs/operations.md.
Documentation
| Install and connect | install options, connecting each agent, sharing with a team |
| Rules and checks | observe mode, command checks, prompt injection, sequences, approvals, undo, spend limits |
| Integrations | MCP proxy, agents by URL, OAuth apps, Python frameworks, HTTP API |
| Operations | dashboard, API, evidence and offline verification, behaviour notes, usage counts |
| FAQ | how it differs from built-in permissions, what if it's down, can an agent get around it |
| Threat model · Claims audit | what it stops, what it doesn't, and the test behind each claim |
| Troubleshooting · Showcase | the first ten minutes; a five-minute demo with a sandbox company |
Status and roadmap
Squidbrake is early and moves fast: releases are frequent, and the rules format can still change between minor versions. Start in observe mode, and read the release notes before upgrading.
Next:
- Reach checks for AWS (#18, design). Before an IAM change runs, work out what the agent can reach afterwards.
- Rule packs for chains.
- Business email compromise: a vendor's bank details change, then a payment goes to that vendor.
- Refunds larger than the order, or sent to a destination changed just before.
- An optional risk model that can only escalate (#16): a second opinion that can hold an action, never allow one.
Tell us what you need most with a 👍 or a comment on the issue.
Contributing, security, license
- CONTRIBUTING.md covers a 10-minute setup and good first issues that name the file and function to change. Hacktoberfest pull requests are welcome. Replaying a real agent incident is a good first one.
- SECURITY.md explains how to report vulnerabilities privately.
- Licensed under the Apache License 2.0.
Metadata
Release files for squidbrake 0.11.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| squidbrake-0.11.1.tar.gz | 300.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| squidbrake-0.11.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 626.6 kB
Release files / squidbrake-0.11.1.tar.gz
| Download URL | squidbrake-0.11.1.tar.gz |
|---|---|
| Size | 300.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4724b2b77c88d637bd9cbdf77b2e1b02cfb427c3def853aa3a967a2f4a4c48aa
|
|
BLAKE2b-256 checksum How to use checksums |
8f5a15a9b58927d3a2b11887b489784df16e4277337652aeb07467f4186b6d68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / squidbrake-0.11.1-py3-none-any.whl
| Download URL | squidbrake-0.11.1-py3-none-any.whl |
|---|---|
| Size | 325.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
892e39de3b6067e50c15c085e353777839c6f29af744548b895898fccb40697e
|
|
BLAKE2b-256 checksum How to use checksums |
e97feeb95cc6518ff0ed41cc60653a33fe254017f0bc61930e281f5d2ff7c4b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log