Back to Blog
AISafetyClaudeCodeDeveloperToolsProductionReadinessGuardrailsAIProductManagement
How I Built Aegis — A Pre-Execution Guardrail That Stopped 43 Irreversible Commands Across 39 Repos
7 min read
Introduction 43 test cases. 39 repos. Zero false-positive complaints. And the only thing standing between my AI coding agent and irreversible damage...
## Introduction
43 test cases. 39 repos. Zero false-positive complaints. And the only thing standing between my AI coding agent and irreversible damage is four PowerShell scripts.
That is Aegis — the deterministic guardrail I built to stop AI coding agents from executing commands you literally cannot undo. Not a monitoring tool. Not a post-mortem framework. A pre-execution block that fires before the damage happens.
I've shipped 6 AI products using Claude Code, and along the way I noticed something that kept me up at night: every AI coding agent can run shell commands with no safety check between "generate" and "execute." This post walks through what I built, why the ALLOW tests matter more than the BLOCK tests, and the framework you can steal for your own repos.
## The Problem
Here's the reality of building with AI coding agents in 2026: they're extraordinary at writing code, running tests, and managing git workflows. And they do all of it by executing shell commands.
But some of those commands are irreversible. Not "dangerous" in the abstract sense — irreversible in the literal sense. You cannot undo them.
A single `>` instead of `>>` silently overwrites your `.env` file. Every secret in that file — gone. A `rm -rf` with a path miscalculation wipes an entire directory tree. A `git push --force` to main rewrites shared history for every collaborator. And a `DROP TABLE` in a production database? That's not a bug report — that's an incident.
The pattern across these commands is specific: **high consequence, irreversible, and plausible as an accidental AI output.** An AI agent won't intentionally destroy your database. But it might generate a cleanup script that uses `rm -rf` with a variable that resolves to the wrong path. And that's enough.
I looked at the existing solutions. System prompts that say "be careful with destructive commands" — those are suggestions, not guardrails. VS Code extensions that flag risky commands after execution — too late. Post-execution audit logs — useful for forensics, useless for prevention.
What I needed was a deterministic chokepoint: a layer that intercepts every command before it executes and blocks the ones that can't be undone. No probabilistic filtering. No LLM reasoning about whether a command is "safe." Just pattern matching against a defined set of irreversible operations.
## The Solution: Aegis
Aegis is a set of Claude Code hooks — specifically, a PreToolUse hook that intercepts every Bash and PowerShell command before execution. The architecture is deliberately simple.
The core mechanism works like this: Claude Code's hook system allows you to register scripts that run before specific tool types execute. When the AI agent generates a shell command, Aegis intercepts it, runs the command string through a set of regex patterns, and returns an exit code. Exit 2 means BLOCK — the command does not execute. Exit 0 means ALLOW — the command proceeds normally.
There are four tiers of protection, each targeting a different class of irreversible operation — from file-level overwrites to database commands. The design principle across all tiers is the same: scope narrowly to the operations you literally cannot undo, and let everything else pass through without interference.
Each tier uses targeted regex patterns to distinguish between irreversible commands and their safe lookalikes. A separate recovery layer automatically backs up high-value files at the start of every session, so even if something slips through an override or an unguarded path, you have a timestamped copy.
## Implementation Details
The entire implementation is four scripts:
`claude-shell-guard.ps1` is the PreToolUse dispatcher. It receives the command string from Claude Code, runs it through the tier pattern matchers, and returns the appropriate exit code. The patterns use bounded regex quantifiers — for eg., `[^>]{0,256}` instead of `.*` — to prevent ReDoS attacks on maliciously crafted command strings.
`claude-session-backup.ps1` is the SessionStart hook. It automatically backs up high-value files to a timestamped backup directory at the start of every coding session.
`deploy-safeguards.ps1` is the per-repo rollout script. It configures `.gitignore` entries for backup directories and installs a pre-commit hook that scans staged files for accidentally committed secrets. The script is idempotent — running it twice produces the same result as running it once.
`test-shell-guard.ps1` and the pre-commit scanner form the 43-case regression matrix: 23 BLOCK and 20 ALLOW. Every code change gets validated against the full matrix before deployment.
The override mechanism is intentionally simple: set `CLAUDE_GUARD_OFF=1` to bypass the guard for one command in one session. For the pre-commit scanner, `git commit --no-verify` skips the secret scan. These escape hatches exist because a guard with no override gets worked around in creative and worse ways.
## Results and Metrics
| Metric | Value |
|--------|-------|
| Total test cases | 43 (23 BLOCK + 20 ALLOW) |
| Test pass rate | 43/43 (100%) |
| Repos deployed | 39 |
| False-positive complaints | 0 |
| Scripts in the system | 4 |
| External dependencies | 0 |
| Cloud services required | 0 |
The 20 ALLOW test cases deserve special attention. These verify that safe commands pass through without interference:
- `rm temp.log` — single file delete, not recursive force
- `git push origin feature-branch` — push to a feature branch, not force-push to main
- `echo "test" >> .env` — append, not overwrite
- `git reset --soft HEAD~1` — soft reset, not hard reset
Before Aegis, every AI-generated command executed immediately with no intermediate check. After Aegis, irreversible commands are blocked before execution, high-value files are backed up at session start, and the guard itself is validated by a 43-case regression matrix.
## Lessons Learned
**The ALLOW tests are harder to write than the BLOCK tests.** It's easy to say "block `rm -rf`." It's much harder to define exactly which `rm` variants should pass through. Every false positive — every legitimate command that gets incorrectly blocked — erodes trust in the guard. And a guard that loses trust gets disabled.
**Escape hatches are a feature, not a bug.** My first instinct was to make Aegis unbypassable — thinking about security, not usability. But Aegis is an accident safety-net, not a security boundary. If a developer needs to run a specific destructive command, the one-command override is better than them disabling the entire system.
**Deterministic beats probabilistic for guardrails.** I evaluated using an LLM to judge command safety — more flexible, could understand context. But LLMs hallucinate, and a hallucinating safety layer is worse than none. Regex is boring, predictable, and never has a bad inference day. For irreversible command blocking, boring is exactly what you want.
## The Pre-Execution Guardrail Framework
If you're building with AI coding agents, here's the framework I extracted from Aegis:
**1. Scope to irreversibility, not danger.**
Don't try to block every "risky" command — that's an impossibly large surface. Block only the ones that can't be undone. If a command's damage is reversible via version control or a simple undo, let it through.
**2. Test the ALLOW paths with equal rigor.**
For every BLOCK pattern, write multiple ALLOW cases that test safe lookalikes. If your ratio is less than 40% ALLOW tests, your guard will generate false positives in production.
**3. Provide explicit escape hatches.**
One-command overrides are better than workarounds. Document them clearly.
**4. Auto-backup the high-value targets.**
Don't wait for something to go wrong. Back up secrets files at session start, every session, automatically.
**5. Use deterministic matching.**
Regex over command strings. No LLM in the guard loop. The guard must be faster than the command it's protecting, and it must never produce a different result on the same input.
## What's Next
Aegis currently covers shell commands. The next tier I'm evaluating is a process gate — a pre-production checklist that runs automated smoke tests against a staging environment before any deployment command executes. The goal is the same: block the irreversible before it happens, not audit it after.
If you're building AI agents that execute commands in production environments, I'd genuinely like to hear what your safety layer looks like. What commands keep you up at night?
## References
1. Claude Code Hooks Documentation — PreToolUse and SessionStart hook types
2. OWASP Top 10 for LLM Applications (2025) — LLM01: Prompt Injection
3. Unicode Technical Standard #39 — Security Mechanisms (ReDoS prevention via bounded quantifiers)