tools capa

tools-shell-guard

A PreToolUse hook on the Bash tool (sprint 4.116, work item 1; requirement 1.1 as re-recorded after Gate 1.5 rounds 1–2, 2026-09-16).

It reads the hook payload on stdin and refuses, with exit 2 and a reason naming the rule, the operations the operator's rules forbid everywhere:

rule idrefusedpasses
git-add-allgit add -A, --all, -u, --updategit add <path>
git-reset-hardgit reset --hardgit reset <path>, git reset --soft
git-checkout-forcegit checkout -f, --forcegit checkout -- <file>, git checkout <branch>
git-stashany git stash but list and showgit stash list, git stash show
drop-databaseDROP DATABASE x, dropdb x unless x ends _fixture or _copyDROP DATABASE x_fixture
psql-live-writeINSERT, UPDATE or DELETE through psql to a database not ending _fixture or _copy, or whose target the command does not statepsql -d x_fixture -c "UPDATE …", a SELECT on live

The rule is global: no repository, path or cwd is exempt. A protected operation reached through a wrapper or indirection (sh -c, eval, env, an absolute path, git -C, a subshell) is refused rather than guessed at — a guard that parses shell semantics loses to the next quoting trick.

What it does read is quoting (first day live, 2026-09-16: a grep for a refused pattern and a SELECT-only here-document were both refused). A quoted word is executed only when an interpreter runs it (sh -c, eval, env, timeout, sudo, xargs…) or when psql reads it as SQL; under grep, echo, printf or git commit -m it is data and passes. For psql the SQL the guard judges is the -c text, a here-document body (it is in the command text) and an echo/printf piped in; a file (-f, <) or a pipe from anything else is opaque and refused on a live target with reason=input-opaque-c or a here-document is the read form.

The decision is pure (decide), so every route is an oracle test. On a refusal the binary also records an observation under the pair rule apply (tools-corpus corpus observation rule-apply), synchronously and best effort: a recorder failure never turns a refusal into an allow, and a refused call runs no tool and leaves no other event. 4.119's governing-refusal predicate reads that row.

Registered in .claude/settings.json under PreToolUse / Bash, beside archive-guard.

Todas las tools · Manual