AI News HubLIVE
In-site rewrite3 min read

Show HN: A pre-execution guard that stops AI agents running destructive commands

Agent Guard is a ~60-line shell hook that catches irreversible commands before an AI agent runs them. It exits 2 to deny, writes the reason to stderr, and works with Claude Code's PreToolUse hook. It blocks git reset --hard, rm -rf, DROP TABLE, and similar destructive commands through an editable regex array, but explicitly does not defend against deliberate obfuscation. It's designed as a seatbelt, not a rollcage, and is MIT licensed.

SourceHacker News AIAuthor: andevandith

Notifications You must be signed in to change notification settings

Fork 0

Star 0

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

6 Commits

6 Commits

docs

docs

LICENSE

LICENSE

README.md

README.md

guard-command.sh

guard-command.sh

install.sh

install.sh

test-guard.sh

test-guard.sh

Repository files navigation

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 → — 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 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.

Resources

Readme

MIT license

Activity

Stars

0 stars

Watchers

0 watching

Forks

0 forks

Report repository