termaxa check reads the command and answers. Try to get a destructive one past it.$ termaxa check "rm -rf ./scratch" press check it, or pick a chip
rm -rf is stopped with the reason and the 12 files it would have taken, and the agent declines to route around it. Recorded on termaxa 0.19.5.wrap reaches it tooherdr plugin install termaxa/termaxa$ brew install termaxa/tap/termaxatermaxa init writes the policy and the hook for whatever harness it finds · termaxa doctor proves it's wired · termaxa replay judges every command your agents have already run, so you know the ask ratio before you commit · termaxa check "rm -rf /" works anywhere, no setupWrite, Edit, Delete or a patch's file headers is judged by the same path rules as a shell command, insured and receipted — and a file no rule names is silence, by design. Cursor's Delete passed through by default until a live capture on Sep 19. (v0.19–0.19.2)echo \" ; terraform destroy matched echo * and was allowed. Live since v0.7.0. Found by unifying two shell parsers and reading what they disagreed about — the disagreements were the bug list. Advisory published. (GHSA-rv66-7qcx-c45j, v0.16)ls -la as a real second user, and the gate decided locally: its hook looked for the supervisor in its own home and found nothing there. The walls held; the door led nowhere. Every automated test had run both halves as the same user. (v0.17)deny, on stdout with exit 0. Fixed the same weekend; the captured payload is a regression test now, and a hard stop lands in Codex's own UI as "Blocked by hook" with the blast radius. (v0.18)termaxa wrap shipped on the promise that a shell resolved by name reaches the gate. Then strace on a real session: Claude Code runs /bin/bash by absolute path when it finds no zsh, and every command walked past the shims with zero audit lines. It honours CLAUDE_CODE_SHELL, so wrap now points it at the shim. Codex runs its login shell by absolute path and offers no such lever; its hooks are the way in, and the docs say so. (v0.18.5)+ the other ten, with dates and versions →
git reset --hard could erase them. State moved to ~/.termaxa, out of git's reach. (v0.8)rm -rf C:\Users\x\Desktop was insured; rm -rf /c/Users/x/Desktop — the same directory — silently wasn't. Found by building the delete preview and comparing the two. They now share one implementation. (v0.14)Delete tool arrived at the hook, matched no write verb, and fell through by default: doomed.txt was deleted with no line in the record. Found by a debug capture on Cursor 3.11.25 the day native writes went live. delete and remove are write verbs now, and the captured payload is the regression test. (v0.19.2)git push*--force*, so git push -f was an ask while --force was a deny. And git -C /path push --force matched no rule at all, hard stop included, because git's global options sit before the subcommand every rule was written for. Found in one live Herdr session where Claude Code spelled every git call with -C. Git's options are stepped over everywhere git is read; force is denied in every spelling. (v0.19.4)is_dir(), which follows links — so a folder holding a junction into a live tree passed the size cap as four files and then copied the whole tree behind it, uncapped, and a rollback would have put the link back as a real directory. That is the mechanism of a public incident that deleted 48,000 files through Windows junctions, inside our own insurance. A link is a link now. (v0.19.4)gh CLI with one line marked "genuinely open question, unverified". Answering it meant measuring both sides. Their side: Claude Code's matcher steps over an env prefix but lets sh -c, eval and xargs run. Ours: with a gh repo delete* deny, the plain form denied and five spellings the head resolver already understood came back as asks, because the string rules never saw the resolver's readings. Every spelling the resolver knows now feeds every rule; sudo is transparent to a deny and never to an allow. (v0.19.5)git branch -M, find -fprint, git diff --output, sed -n -i and inline node -e, each allowed with no prompt, no preview and no backup. Reproducing them turned up sed's e command, which runs any shell command under the same allow. And a push that deletes remote branches asked, but its preview said "nothing to push". Now the option that writes or runs turns the allow into an ask that names it, the file it would write is previewed and backed up first, and a push that removes refs says which. Published as GHSA-36jf-95xr-37f2, credited to him. (v0.19.6)open source under MIT / Apache-2.0
no feature gates. no license keys. ever.
cloud sits on top of the free core, never in front of it.
solo maker · builds developer infrastructure
I build with Claude Code every day, and I kept getting nervous handing it commands that touch git history and production databases. The built-in "allow this command?" prompt tells you what it wants to run — not what will actually happen.
So I built the thing I wanted: a gate that shows the real consequence, takes a backup before you approve, and lets you roll back. The first time I pointed a live agent at it, the agent chained a destructive command behind a harmless one and slipped past a naive rule. Watching that happen is why Termaxa now splits compound commands and judges each part — that exact bypass is a regression test today.
termaxa 0.21.7