overview / rules / baseline-rm-rf-outside
baseline-rm-rf-outsideA recursive delete outside the project tree cannot be undone by git.
a recursive rm whose target lands outside the project tree and outside the system temp area. The target is resolved, not pattern-matched: .., ~ and a symlinked parent land where they really land, and a wildcard or a brace is expanded the way a shell expands it before it is judged — rm -rf /tmp/*/../../Users/you/work is refused because every word it expands to leaves the temp area, while rm -rf /tmp/build-*/out passes. The temp carve-out is your scratch, not the shared root's contents: under /tmp, /var/tmp or $TMPDIR the first component of the target must be a name you wrote, so rm -rf /tmp/scratch-* and rm -rf /tmp/proj-out/* pass while rm -rf /tmp/*, rm -rf /tmp/*.log and rm -rf /tmp/*/x are refused — they name another session's mktemp tree as surely as your own. $TMPDIR is read from the environment, which is the one input an agent writes for itself, so a root named there is honoured only when it lands inside the machine's real temp area (/tmp, /var/tmp, /var/folders) and not under $HOME: TMPDIR=/usr/local rm -rf /usr/local/lib and TMPDIR=/srv rm -rf /srv/www are refused, because an assignment does not make a directory disposable. The cost, stated: an unusual $TMPDIR such as /run/user/1000 is no longer read as scratch, and a recursive delete there is refused when it is also outside the project tree — silence baseline-rm-rf-outside by id if that is your setup. rm -rf ./build and rm -rf node_modules pass.
From the floor table in docs/guard.md.
A guard with no way out is a trap, so here is the way out, measured on 2026-08-30 rather than asserted. Deleting a project of your own that carries its own .rabadon is ordinary work and passes — rm -rf ./old-project, mv ./old-project /tmp/bin, both held by assertion in native/law_family_test.sh. The subject of this rule is the law, not the tree around it.
For a leftover somewhere else on the disk, the refusal now names the rule that is actually speaking, which before today it did not:
Both of those work, and so does disabled: ["baseline-law-unmade"] for the law itself — that path is asserted in the suite too, because an override named in every refusal message that does not actually open the door is worse than no override at all. RABADON_OFF=1 <command> is NOT one of them: an env prefix is part of the command text and the gate reads it as a silencer being spelled at it. That spelling was published by an earlier phase and is wrong; use rabadon off.
Rendered from the strings in native/baseline.h and the envelope in native/gate_pre.h (Judge::refuse). A word in <angle brackets> is filled in from the command at the moment it is refused.
Only the user can switch it off, by id, in the project's guard:
or by pausing supervision with rabadon off, which records the change. Every other rule keeps running.
70 of the 778 records in the published field dataset (field.jsonl, 2026-07-27 to 2026-08-26) carry this id. STOP is a refusal in enforce mode; WOULD_BLOCK is the same verdict recorded in watch mode, where nothing is stopped.
| event | records |
|---|---|
| WOULD_BLOCK | 70 |
Counted from field.jsonl, the file the field page is built from.
rabadon on | off | status | toggle