Apache-2.0 · Python 3.9+ standard library · no pip dependencies

Governance-as-code for AI coding agents

Deterministic, fail-closed checks that run before a tool call does: secrets, private paths, destructive commands, exfiltration, and a human sign-off for git push. Built for Claude Code and adaptable to other agent harnesses. Written to say plainly what it cannot stop.

Two engines, kept separate

Prompts guide an agent; they do not hold when the agent is being manipulated. So the repo splits the job.

The Brain: in-context skills

Three optional SKILL.md packages: safe-agent-coder (blast-radius tiers, tests before claims), untrusted-data-guard (treat fetched text as data, keep the Rule of Two) and governance-auditor (self-audit against the matrix). Guidance only. Nothing here is enforced.

The Brakes: runtime hooks

A PreToolUse hook inspects each call and exits 2 to block, 0 to allow. Any crash, bad config, missing pack or changed policy also exits 2. A PostToolUse hook keeps a hash-chained audit log.

What the hook checks

35 rules in five swappable policy packs, across four tiers. Rules read the decoded tool input, not just the raw JSON, and normalise quotes, zero-width characters, SQL comments and whitespace first.

TierExamplesWhy it can be decided per call
Global (10)API keys, private-key headers, SSNs, Luhn-valid card numbers and SINsA secret in an argument is visible before it is written or sent.
PathYour denylisted folders, the approval secret and receipt, and writes to guardrails config, packs, source and harness settingsThe target path is in the call.
Command (20)terraform destroy, DROP TABLE, force-push, rm -rf of / or ~, curl | sh, reverse shells, upload commandsThe command text is the call.
Outbound (5)Personal finance, health or housing terms in Gmail or Buffer-style publishing tools onlyApplies only to tools that leave your machine.

Every rule is tested in pairs: what must be blocked and what must still be allowed.

BlockedStill allowed
block git -C . push origin main (needs approval)allow git commit -m "fix push notification bug"
block rm -r -f ~allow rm -rf ./node_modules
block kubectl --context prod delete ns paymentsallow kubectl delete pod web-1 --namespace dev
block python3 <<PY import urllib.request …allow node build.js --env=prod --target internet

The approval gate

git push and git remote add are held until a human mints a receipt from an interactive terminal. Receipts are HMAC-signed, single-use, scoped to one action and capped at 60 minutes. A receipt clears only the rule it was minted for, so git push && rm -rf ~/ is still blocked. Force-push, terraform destroy and the other destructive commands have no approval path at all.

python3 guardrails.py approve --scope git_remote_push --ttl 15   # you, in your own terminal

Scope: what a tool-call hook can decide

The MIT AI Risk Repository has 24 risk subdomains. It does not say which a runtime hook can decide, so the repo publishes its own row-by-row classification and labels it as such.

5decidable at the tool-call boundary
3decidable in part
16not decidable, not claimed
18risk and control rows, each cited to ARC, OWASP and MIT

Matrix rows without enforcing code are marked "not enforced". See the classification and framework mapping.

A tripwire, not a sandbox

Read this before relying on it. The full list is in limitations.md.

  • An agent running as your own OS user can still approve its own actions (by faking a terminal or writing its own code). The gate catches accidents; a real boundary needs the secret kept away from that user.
  • Pattern matching misses shell indirection: variables, cd then a relative path, globs.
  • An agent able to rewrite the engine's source from a shell can remove the checks. Install the clone where the agent's user cannot write.
  • The audit log's hash chain detects naive edits only. Ship records somewhere the agent cannot write.
  • For real isolation use a rootless container, a VM or a separate user.

How it was checked

The first draft went through two adversarial review rounds (AI-assisted red-teaming with working payloads against the real code). Each finding became a permanent test.

179unit tests
44case DLP regression suite
0pip dependencies

Quick start

Run these in your own project. Re-run install-hooks after any edit to guardrails.json or a pack, or every tool call fails closed.

git clone https://github.com/Charitarth1/agent-guardrails.git
cd your-project
python3 ../agent-guardrails/guardrails.py init            # creates ./guardrails.json
python3 ../agent-guardrails/guardrails.py install-hooks   # wires .claude/settings.json + AGENTS.md
python3 ../agent-guardrails/guardrails.py vendor-skills --target claude-code   # optional skills
# restart Claude Code, then:
python3 ../agent-guardrails/guardrails.py check --tool Bash --payload "terraform destroy"