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

andevandith1 pts0 comments

GitHub - vandith1/agent-guard: A pre-execution guard that stops your coding agent running destructive commands. One shell file, no dependencies. · GitHub

/" data-turbo-transient="true" />

Skip to content

Search/

Sign in<br>Sign upAppearance settings

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

vandith1

agent-guard

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>6 Commits<br>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

View all files

Repository files navigation

agent-guard

Your coding agent will eventually run git reset --hard, force-push to main, or<br>drop a table. Not because it's careless — because it's confident, and the loop<br>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<br>before every shell command the agent proposes, exits 2 to deny, and writes the<br>reason to stderr — which agent CLIs feed back into the loop, so the agent stops<br>retrying and surfaces the command to you instead.

BLOCKED by guard [discard all local changes (git reset --hard)]<br>command: git reset --hard HEAD~3<br>This one is gated to the human. Do not retry, do not reword.<br>Surface the exact command and let the human run it.

Install

bash install.sh # merges a PreToolUse hook into .claude/settings.json<br>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<br>shell hook before a tool call and respects its exit code. Requires bash,<br>grep -E, and python3.

What it blocks

git reset --hard · rm -rf · git clean -f/-x · git checkout . ·<br>git filter-branch · force-push to main/master/production · DROP TABLE ·<br>TRUNCATE · FLUSHALL · aws delete-*/terminate-* · kubectl delete ·<br>terraform destroy · docker … prune · chmod 777 · curl … | sh ·<br>raw writes to /dev/sd*.

Rules live in one array at the top of the script as label@@regex pairs. Edit<br>them. Add a test case when you do — including a benign command the new pattern<br>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<br>failure mode I actually hit — the loop drifted three steps ago and the next command discards a<br>day's work.

It does not stop: anything deliberately evading it. g""it reset --hard, a base64 payload<br>through eval, a shell script, an alias. The matcher is a regex over the proposed command string,<br>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<br>obfuscating commands to get around a hook you installed, a pattern list is not your problem. This<br>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<br>machine: server-side branch protection, least-privilege credentials, and backups. Nothing here is a<br>substitute for any of those. Use them, and use this for the irreversible operations they do not<br>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<br>that quotes a gated phrase gets blocked. That's deliberate: the alternative is<br>parsing shell quoting, expansion and eval, and every parser is a new way to<br>slip a command past the guard. Fail-safe beats clever. The habit that fixes it:<br>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<br>blocks. A guard that silently degrades to "allow everything" is worse than no<br>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<br>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<br>reviewable and reversible. These shouldn't be banned — they should be gated,<br>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<br>agent can't touch, including refreshing its...

guard command agent reset hard commands

Related Articles