An AI assistant that can run commands will run the command it believes is correct, at the speed of a command. It has no sense of dread. The difference between a helpful session and an expensive one is not how good the model is; it is whether the action it took can be taken back.
The idea
Sort every action by whether you can undo it, and give supervision to the ones you cannot. A code edit is reversible, because git holds the previous version. A deleted production table is not, unless a backup exists and you have restored from it before. Anything that leaves your machine and reaches other people, such as an email send or a payment capture, is not reversible at all, since you cannot unsend it. Reversibility, rather than danger, is the useful test, because it tells you which actions to sit in front of.
reversibility examples supervision
free to undo edit a file, install a package let it run
(git holds the old copy) run tests, read logs
undoable with effort force-push, drop a local table read first,
(backup, reflog, redeploy) revert a deploy then approve
cannot be undone email to real users human types it
delete production rows
a migration on live data
a revoked credentialHow it works
Five categories account for nearly all of the real damage.
- Deleting data.
rm -rf,DROP TABLE,DELETEwithout aWHEREclause, emptying a storage bucket. The command succeeds silently, which is the problem: there is no confirmation step and no recycle bin. - Touching production directly. A live server, the production database, the DNS records for your domain. A change here has an audience immediately.
- Credentials. Reading, printing, or rotating a key. An assistant that reads
.envto debug a connection has now put your secrets into the transcript of the session, and possibly into the vendor's logs. - Migrations on live data. A A file that changes the shape of the database, such as adding a column or renaming a table. It runs against real rows, so a wrong one can lose them. that drops a column removes the data in it. Running it against production is a one-way action even when the file itself is in git.
- Sending email to real users. Nothing recalls a broadcast. A test that accidentally uses the live list is the classic version of this.
git push --force sits at the edge. It is recoverable through the reflog on a machine that still
has the old commits, and unrecoverable if the only copy of that branch was the remote one.
What to do
- Turn off blanket permission for shell commands and keep a short allowlist of read-only ones. In
Claude Code,
/permissionsis where the allow and deny lists live; the deny list is the place forrm -rfand for reads of.env. - Point Claude Code at a development database, never the production connection string, and keep the production credentials out of the project directory entirely.
- When a destructive step is genuinely needed, ask for the command rather than the execution: "Write the migration and the rollback, and show them to me. Do not run either." You paste it yourself.
- Take a backup before the irreversible step, and confirm the backup restores. An untested backup is a belief, not a safeguard.
Where it breaks
Supervision only works if you read what you approve. A prompt that asks for confirmation twenty times an hour trains you to press yes, which is how a wrong command gets approved by a person who was technically supervising. Narrow the allowlist so the prompts become rare enough to actually read. The other limit is scope: an assistant working with a legitimate database connection can issue a destructive statement without ever running a shell command, so a shell deny list alone does not protect the data. Least-privilege database credentials do the part that permission rules cannot.