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.

code
  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 credential

How it works

Five categories account for nearly all of the real damage.

  • Deleting data. rm -rf, DROP TABLE, DELETE without a WHERE clause, 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 .env to 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 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

  1. Turn off blanket permission for shell commands and keep a short allowlist of read-only ones. In Claude Code, /permissions is where the allow and deny lists live; the deny list is the place for rm -rf and for reads of .env.
  2. Point Claude Code at a development database, never the production connection string, and keep the production credentials out of the project directory entirely.
  3. 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.
  4. 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.