# agent-guard Your coding agent will eventually run `git reset --hard`, force-push to main, or drop a table. Not because it's careless — because it's confident, and the loop drifted three steps ago. **[Try it in your browser →](https://vandith1.github.io/agent-guard/)** — paste any command, see whether it would be blocked and by which rule. Nothing is sent anywhere; the rules run locally. This is a ~60-line shell hook that stops the commands you can't undo. It runs before every shell command the agent proposes, exits 2 to deny, and writes the reason to stderr — which agent CLIs feed back into the loop, so the agent stops retrying and surfaces the command to you instead. ``` BLOCKED by guard [discard all local changes (git reset --hard)] command: git reset --hard HEAD~3 This one is gated to the human. Do not retry, do not reword. Surface the exact command and let the human run it. ``` ## Install ```bash bash install.sh # merges a PreToolUse hook into .claude/settings.json bash test-guard.sh # 6 assertions, should be 6 passed / 0 failed ``` Works with Claude Code's `PreToolUse` hook, and with any agent CLI that runs a shell hook before a tool call and respects its exit code. Requires `bash`, `grep -E`, and `python3`. ## What it blocks `git reset --hard` · `rm -rf` · `git clean -f/-x` · `git checkout .` · `git filter-branch` · force-push to main/master/production · `DROP TABLE` · `TRUNCATE` · `FLUSHALL` · `aws delete-*`/`terminate-*` · `kubectl delete` · `terraform destroy` · `docker … prune` · `chmod 777` · `curl … | sh` · raw writes to `/dev/sd*`. Rules live in one array at the top of the script as `label@@regex` pairs. Edit them. Add a test case when you do — including a benign command the new pattern must *not* catch. That's how you find an over-greedy regex before it finds you. ## What this does and does not stop **It stops:** a confident agent proposing an irreversible command in plain text, which is the failure mode I actually hit — the loop drifted three steps ago and the next command discards a day's work. **It does not stop:** anything deliberately evading it. `g""it reset --hard`, a base64 payload through `eval`, a shell script, an alias. The matcher is a regex over the proposed command string, and a regex loses to an adversary every time. That distinction is the whole threat model, and it is worth being blunt about: if your agent is obfuscating commands to get around a hook you installed, a pattern list is not your problem. This assumes a well-intentioned model having a bad moment, not a hostile one. It also does not replace the things that are strictly more reliable because they sit outside your machine: server-side branch protection, least-privilege credentials, and backups. Nothing here is a substitute for any of those. Use them, and use this for the irreversible operations they do not cover — a hard reset on uncommitted work, a recursive delete, a dropped table, a destroyed stack. A seatbelt, not a rollcage. ## Two things worth knowing **It matches the whole command string, arguments included.** So a commit message that quotes a gated phrase gets blocked. That's deliberate: the alternative is parsing shell quoting, expansion and `eval`, and every parser is a new way to slip a command past the guard. Fail-safe beats clever. The habit that fixes it: `git commit -F .commit-msg` instead of `-m "…"`, never a heredoc. **It fails closed.** If it can't read the command out of the hook payload, it blocks. A guard that silently degrades to "allow everything" is worse than no guard, because you'd stop watching. ## The idea behind it: two tiers Destructive commands and *external-effect* commands are different problems. - **Tier 1** — `rm -rf`, `reset --hard`, `DROP TABLE`. Unrecoverable. Never negotiable, no unlock, not even for you-in-a-hurry. This repo is tier 1. - **Tier 2** — `git push`, `npm publish`, deploys, migrations. Real effects, but reviewable and reversible. These shouldn't be *banned* — they should be gated, unlockable by a human for a short window that auto-relocks. Tier 2 is where the design gets interesting: the unlock has to be something the agent can't touch, including refreshing its timestamp to extend the window or deleting it to hide that it was used. --- The full kit adds tier 2 with the time-boxed unlock, a config file, a git pre-push hook, an isolation workflow, a merge gate that catches prompt regressions with a deterministic grader, and the incident write-ups behind each rule: https://andevan.gumroad.com/l/agent-control-kit MIT licensed. Take it, fork it, ship it in your own tooling.