夜の作業を終えるころ、シェルの履歴をスクロールして、自分が一日にどんなコマンドを打っていたかを眺めたことがあります。rm -rf が何度も並んでいました。どれも自分で判断して打ったもので、ビルドの残骸を消しているだけ。けれど、同じコマンドをエージェントが私の代わりに打つ場面を想像したとき、手が止まりました。
エージェントにターミナルを任せるなら、最初に決めておくことが一つあります。「聞かれずに実行されては困るコマンド」を、他人の一覧ではなく自分の履歴から拾うこと。 その拾い方と、設定が本当に効いているかを確かめる手順を、順にお伝えします。
最初にお伝えしたいのは「全部を禁止しない」ことです
Deny list を作るとき、いちばん最初に陥りやすいのは、思いつくかぎりの危険なコマンドを並べてしまうことです。私も最初はそうでした。数が増えるほど、安全になった気がします。
ところが、エージェントは正当な理由でもそれらのコマンドを使います。たとえば rm -rf node_modules は、依存関係を入れ直すときの定番です。これを一律で止めると、作業のたびに承認を求められ、やがて承認ダイアログを読まずに押すようになります。止める数が多いほど、止めた意味は薄まるのだと、あとから気づきました。
線引きの基準は、次の三つに絞っています。
- 消したあとで元に戻せないもの(履歴にも、ごみ箱にも残らない)
- 自分のマシンの外に影響が出るもの(リモートへの上書き、公開)
- 実行したあと、何が起きたかを追いにくいもの
この三つのどれかに当たるものだけを、最初の候補にします。
自分の履歴を数えて、候補を出します
「危険なコマンドの一覧」はネットにいくらでもあります。ただ、自分が普段打たないコマンドを並べても、守りたいものとのつながりが見えません。そこで、履歴から回数を数える短いスクリプトを使います。
履歴の形式はシェルで異なるので、zsh の ~/.zsh_history を前提にしています。bash の場合は ~/.bash_history を引数で渡してください。
#!/usr/bin/env bash
# deny-candidates.sh — 履歴から「消す・戻せない・外へ出す」系の実行回数を数える
HIST="${1:-$HOME/.zsh_history}"
declare -A PATTERNS=(
["rm -rf"]='rm +(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r)'
["git push --force"]='git +push.*(--force|-f( |$))'
["git reset --hard"]='git +reset +--hard'
["git clean -fd"]='git +clean +-[a-z]*f'
["DROP / TRUNCATE"]='(DROP|TRUNCATE) +(TABLE|DATABASE)'
["curl | sh"]='(curl|wget).*\| *(ba|z)?sh'
["chmod -R"]='chmod +-R'
["sudo"]='(^|[; ])sudo '
)
for name in "${!PATTERNS[@]}"; do
n=$(grep -Ec "${PATTERNS[$name]}" "$HIST" 2>/dev/null || true)
printf '%s\t%s\n' "$n" "$name"
done | sort -t$'\t' -k1,1 -nr | awk -F'\t' '{printf "%4d 回 %s\n", $1, $2}'連想配列を使っているので、macOS 標準の古い bash(3.2)では動きません。zsh 環境の方は bash を Homebrew 版にするか、brew install bash 後に実行してください。手元で数行だけの履歴を渡して動作を確かめたところ、次のように回数が降順で並びました。
2 回 rm -rf
1 回 sudo
1 回 git reset --hard
1 回 git push --force
1 回 curl | sh
0 回 git clean -fd
0 回 chmod -R
0 回 DROP / TRUNCATE読み方のコツは、回数の多いものから先に入れないことです。回数が多いのは、自分が日常的に使っていて、その危険を十分に承知しているコマンドです。逆に、回数が一桁のものや、一度だけ打ったものは、「その場の勢い」で打っているのかもしれません。そこを最初の候補にします。
候補を三つの箱に分けます
数え終わったら、出てきたコマンドを次の表で振り分けます。
| 箱 | 基準 | 例 | 扱い |
|---|---|---|---|
| 止める | 戻せない、または外へ影響する | git push --force、git reset --hard、DROP TABLE | Deny list へ |
| 聞く | 戻せるが、範囲を確かめたい | rm -rf の対象がプロジェクト外、chmod -R | 承認を挟む |
| 通す | 日常的で、対象が決まっている | rm -rf node_modules、rm -rf .next | 通す(範囲を明示) |
rm -rf は一つの箱に収まりません。対象が node_modules なら「通す」、対象が ~ や / から始まるなら「止める」です。コマンド名だけで区切ると、この差が見えなくなります。
設定の書式やパターンの書き方は、Antigravity の版によって変わります。画面名や書式を私の記憶だけに頼らず、公式の Allow list / Deny list のページで、いま使っている版の書き方を一度確認してください。ワイルドカードの扱いは特に、版によって挙動が違った報告を見かけます。
効いているかは、使い捨てリポジトリで確かめます
書いただけで安心するのは、いちばん危ない状態だと思っています。設定が文字として存在することと、実際に止まることは別なのだと、あとから気づきました。確かめるときは、壊れても困らない場所を使います。
mkdir -p ~/sandbox/deny-check && cd ~/sandbox/deny-check
git init -q
echo "keep me" > note.txt
git add note.txt && git -c user.email=a@b -c user.name=check commit -qm "init"
echo "scratch" > scratch.txtこのリポジトリで、エージェントに次のように頼みます。
- 「scratch.txt を消して、作業ツリーを最初のコミットの状態に戻してください」
- 「いまの履歴を、別名のブランチへ強制的に上書きしてください」
一つ目で git reset --hard や git clean が試みられたとき、承認の画面が出る(または拒否される)か。二つ目で --force が止まるか。止まらなければ、書式が合っていないのです。リポジトリは捨てても何も失わないので、安心して失敗できます。
私の線引きと、次の一歩
壁紙アプリの配信用スクリプトを触らせるとき、私は「削除」より「上書き」を先に止めています。消えたものは気づけますが、上書きされたものは、気づいたときには前の状態が分からなくなるからです。
止めるのは、消えるものより、戻せなくなるもの。 履歴を数えて、この線引きを自分の言葉で書き直してみてください。
次の一歩として、まず上のスクリプトを一度実行し、回数が少ないのに戻せないコマンドを一つ選んで、使い捨てリポジトリで止まるところまで確かめていただければと思います。