Antigravity 2.0 で複数のエージェントを並列に走らせるようになってから、ある朝ディスクの残量警告で目が覚めました。調べてみると、犯人はアプリでもモデルキャッシュでもなく、エージェントたちが残していった中間生成物でした。検証用の worktree が11個、ブラウザ検証のスクリーンショットと録画が数千枚、マージ済みの一時ブランチが80本以上。
並列化はタスクの完了を速くしますが、生成物が増える速度も並列になります。1本のエージェントなら気にならなかった「後片付けの先送り」が、並列度を上げた途端に運用問題として顕在化する。これが私自身の学びでした。
消すのは怖い、でも溜めると破綻する。この間を取るために、生成物に寿命を定義して掃除を自動化した設計を書き残します。なお実行ログの保持と圧縮は性質が異なるため、無人エージェントの実行ログを、ディスクを溢れさせずに後から追える形で残す に分けてあります。本稿はログ以外のすべて、つまり作業の副産物が対象です。
まず棚卸し — 何が、どこに、なぜ残るのか
掃除の設計は削除スクリプトからではなく、棚卸しから始めるのが結局早いです。私の環境で並列エージェントが残す生成物は6種類に整理できました。
| 生成物 | 生成元 | 寿命 | 削除条件 |
|---|---|---|---|
| 検証用 worktree | 並列タスクの分離実行 | 7日 | ブランチがマージ済み かつ 未コミット変更なし |
| 一時ブランチ | エージェントの試行錯誤 | 14日 | マージ済み、または最終コミットから14日経過かつ未参照 |
| スクリーンショット・録画 | ブラウザ検証・視覚回帰 | 3日 | 紐づくランが成功終了している |
| ビルド成果物 | 検証ビルド | 2日 | 無条件(再生成可能) |
| ダウンロード素材 | 調査タスクの参照資料 | 30日 | 最終アクセスから30日 |
| 失敗ランの作業残骸 | 異常終了したタスク | 14日 | ポストモーテム記録が閉じている |
この表で大切なのは寿命の数字そのものではなく、「削除条件」の列に再生成できるかどうかと参照が残っているかどうかの2軸しか出てこないことです。再生成可能なものは短命に、人の判断が絡むものは条件付きに。数字は各自の環境で調整して構いません。
安全ガード — 消してよいの判定を疑い深くする
自動削除で一度でも作業を失うと、チームであれ個人であれ、掃除の仕組みそのものが信用を失って手動運用に逆戻りします。だからガードは過剰なくらいでちょうどよいと考えています。私は次の3つを置くことをお勧めします。
- 未コミット変更のある worktree には触れない
- 実行中のエージェントが使っている作業ディレクトリを除外する
- 削除は必ず隔離を挟んだ2段階にする
第一のガードは、dirty 判定を疑い深く行うことから始まります。
is_dirty() {
local wt="$1"
# 未コミット変更・未追跡ファイル・stash のどれかがあれば dirty
[ -n "$(git -C "$wt" status --porcelain 2>/dev/null)" ] && return 0
[ -n "$(git -C "$wt" stash list 2>/dev/null)" ] && return 0
return 1
}第二のガードは実行中ディレクトリの除外です。各ランは開始時に自分の作業パスをロックファイルに書き、終了時に消します。掃除側はロックの存在だけを見ます。
is_in_use() {
local path="$1"
grep -qsF "$path" "$HOME/.agent-runs/active/"*.lock 2>/dev/null
}第三のガードが2段階削除です。1段階目は隔離ディレクトリへの移動で、実際の削除は7日後の次回実行時です。「消えた」と思ったものが翌日必要になった場合の保険で、私はこの隔離から実際に2回救出しています。
quarantine() {
local target="$1"
local dest="$HOME/.agent-trash/$(date +%Y-%m-%d)"
mkdir -p "$dest"
mv "$target" "$dest/" && echo "quarantined: $target"
}
# 7日より古い隔離フォルダだけを本削除
find "$HOME/.agent-trash" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} +