CLAUDE LABEN
SUNSET — 旧 Workbench と実験的プロンプトツール API の廃止は明日8月17日です。残り1日となりましたLATEST — 最新は8月15日の v2.1.233 です。GitLab のマージリクエスト URL が --worktree と claude agents で扱えるようになり、MR は !N 形式で表示されますSECURITY — Windows で NT の \??\ デバイスプレフィックスを含むパスが UNC 検証をすり抜ける問題が直りました。NTLM 資格情報が漏れる経路が塞がれていますTODO — Opus 4.8・Sonnet 5・Fable 5・Mythos 5 以降では TodoWrite と Task 系ツールが既定で無効になりました。CLAUDE_CODE_ENABLE_TODO_TOOLS=1 で戻せますFORK — 8月14日の v2.1.232 で subagent_type: 'fork' が既定になり、会話全体とプロンプトキャッシュをそのまま引き継げるようになっていますMENTION — プロンプトで @ を打つと別のセッションを名前で呼び出せます。SendMessage がそのセッションへ直接届きますSUNSET — 旧 Workbench と実験的プロンプトツール API の廃止は明日8月17日です。残り1日となりましたLATEST — 最新は8月15日の v2.1.233 です。GitLab のマージリクエスト URL が --worktree と claude agents で扱えるようになり、MR は !N 形式で表示されますSECURITY — Windows で NT の \??\ デバイスプレフィックスを含むパスが UNC 検証をすり抜ける問題が直りました。NTLM 資格情報が漏れる経路が塞がれていますTODO — Opus 4.8・Sonnet 5・Fable 5・Mythos 5 以降では TodoWrite と Task 系ツールが既定で無効になりました。CLAUDE_CODE_ENABLE_TODO_TOOLS=1 で戻せますFORK — 8月14日の v2.1.232 で subagent_type: 'fork' が既定になり、会話全体とプロンプトキャッシュをそのまま引き継げるようになっていますMENTION — プロンプトで @ を打つと別のセッションを名前で呼び出せます。SendMessage がそのセッションへ直接届きます
記事一覧/Claude Code
Claude Code/2026-07-14中級

空の変数と rm -rf の夜 — Claude Code auto モードの事前確認に助けられた片付けの記録

空になった変数のせいで rm -rf が広範囲に化けかけた夜の記録です。set -u が空文字を素通りさせる理由を手元のシェルで検証し、ドライランを既定にした掃除スクリプトの実行結果まで残しました。

Claude Code222auto mode3個人開発112運用13安全設計

深夜、いくつものアプリ用リポジトリに溜まったビルドキャッシュを一掃したくて、その片付けを Claude Code に任せていました。

DerivedData、CocoaPods の Pods、React Native 側の node_modules.build。個人開発で複数のアプリを並行して抱えていると、こうした中間生成物がディスクを静かに侵食していきます。

一つずつ手で消すのは退屈な作業です。だからこそエージェントに向いている——そう思っていました。

途中、ターミナルの表示が一瞬止まりました。実行されようとしていたのは、こういう形のコマンドでした。

rm -rf "${CACHE_ROOT}"/*

CACHE_ROOT が、空でした。展開すれば rm -rf /* に化けるコマンドです。手が、少し冷たくなりました。

変数が空になっていた理由

原因はありふれたものでした。

掃除のスクリプトは、リポジトリごとにキャッシュの場所を環境変数へ入れてから回す設計にしていました。ところが対象の一つは、少し前にディレクトリ構成を変えたばかりのアプリでした。

想定していたパスが存在せず、CACHE_ROOT を組み立てる段階で値が入らなかったのです。シェルは未定義の変数を黙って空文字列として扱います。エラーも警告も出ません。

rm -rf "${CACHE_ROOT}"/* は、意図としては「このアプリのキャッシュだけを消す」でした。けれど空文字列に化けた瞬間、意味はまるで違うものになります。

個人開発では、テストもレビューも自分一人です。こういう取り違えを止めてくれる第二の目が、普段はいません。

空文字は set -u をすり抜ける — 手元で確かめた四つの組み合わせ

あの夜のあと、どうしても腑に落ちない点が残りました。

私は掃除スクリプトの先頭に set -euo pipefail を書いていました。-u は未定義の変数を使ったらそこで止まる、という指定です。それなのに、なぜ空の CACHE_ROOT は素通りしたのか。

気になったので、まっさらな bash 5.1.16 で確かめてみました。まず、空変数がどこまで広がるのかを、削除ではなく引数の数として観測します。

# 実際には消さず、展開結果だけを数える
unset CACHE_ROOT
set -- "${CACHE_ROOT}"/*
echo "引数の数: $#"
echo "先頭3件: $1 $2 $3"

手元での出力はこうなりました。

引数の数: 25
先頭3件: /bin /boot /dev

25 という数字は、ルート直下のエントリ数です。「うっかり広い範囲を消しかけた」という曖昧な言い方をしていた事故が、25 個の起点という具体的な形で目の前に出てきました。

続けて、変数の状態と防御の組み合わせを総当たりで試しました。

変数の状態防御結果
未定義(unsetset -u止まる(bash: unbound variable)
未定義(unset${VAR:?}止まる
空文字を代入(VAR=""set -u止まらない(そのまま通過)
空文字を代入(VAR=""${VAR:?}止まる

三行目が答えでした。

set -u が見ているのは「その変数が定義されているか」であって、「中身があるか」ではありません。私のスクリプトはパスの組み立てに失敗したとき、変数を未定義のままにするのではなく、空文字を代入していました。定義はされている。だから -u は何も言わなかったのです。

${VAR:?メッセージ} のほうは、未定義と空文字の両方を弾きます。値を使う直前に一行置くだけで、この差が埋まります。

: "${CACHE_ROOT:?CACHE_ROOT が空です}"

ひとつ注意点があります。この停止の終了コードはシェルによって違いました。同じ条件で bash は 127、dash は 2 を返します。「特定の番号を見て分岐する」書き方をすると、実行環境が変わった瞬間に検知をすり抜けます。終了コードは非ゼロかどうかだけで判断するのが安全です。

auto モードが「文脈から解決できない変数」を見ていた

止めてくれたのは、Claude Code の auto モードでした。

2026年7月のアップデートで、auto モードはいくつかの安全側の挙動を既定に加えています。その一つが、文脈から値を解決できない変数を含む rm -rf は、実行前に確認を挟むというものです。

エージェントは CACHE_ROOT に確かな値を結び付けられませんでした。だから黙って走らせず、私に判断を返してきたのです。

ここで大切なのは、単純な「破壊的コマンドは全部止める」ではない点だと感じています。それでは確認が多すぎて、結局は読まずに承認する癖がつきます。

見ているのは「文脈から解決できるか」でした。値の裏付けが取れない削除だけを拾い上げる。この線引きは、任せる側の集中力を消耗させない配慮のように思えました。

あわせて、auto モードはセッション記録そのものの改ざんもブロックするようになっています。何を実行したかの痕跡が後から書き換えられない——放置気味に回す作業ほど、この一線は効いてきます。

Opus 4.8 に長い片付けを任せた手触り

同じ日、Claude Opus 4.8 が一般提供になりました。コーディングやエージェント的な作業、そして長い手順の一貫性が底上げされたモデルです。

今回の掃除は、リポジトリ数だけ手順が繰り返される、地味に長い仕事でした。各リポジトリでキャッシュ場所を確認し、消してよいものを見極め、消す。この往復を最後まで文脈を保ったまま進めてくれたのは、素直に助かりました。

一方で、任せきりにはしていません。

削除対象の一覧を、実行の前に必ずテキストで出してもらう。これは私が指示に加えた手順です。モデルが賢くなるほど、私の側の「確認の型」を明文化しておくことが効いてくると感じています。

削除に入る前の対象確認を、擬似コードで表すとこうなります。

# 消す前に、対象を必ず可視化してから承認する
for repo in "${REPOS[@]}"; do
  cache="${repo}/build-cache"
  # 値の裏付けが取れないパスは、そもそも削除ループに渡さない
  if [ -z "${cache}" ] || [ ! -d "${cache}" ]; then
    echo "skip: ${repo}(キャッシュ未確認)"
    continue
  fi
  echo "delete candidate: ${cache}"
done

[ -z "${cache}" ] の一行が、あの夜の空変数を弾く砦です。auto モードの事前確認と、自分のスクリプト側の防御。二重にしておくと、夜間に任せていても落ち着いていられます。

自分の運用に落とし込んだ確認ルール

今回の一件のあと、片付け系の作業をエージェントに任せるときの約束事を、いくつか言葉にしました。

場面決めたこと
削除の直前対象の絶対パス一覧を必ずテキスト出力し、目で確認してから承認する
変数の扱いパスを組む変数は空チェックを必須にし、空ならその対象をスキップする
権限rm -rf を含む手順は auto モードの事前確認を無効化しない
記録実行ログは改ざん不可の前提で残し、翌朝に何を消したか追える状態にする

特別なことは何もありません。けれど個人開発の現場では、この当たり前を仕組みとして持っておけるかどうかが、安心して手を離せるかの分かれ目になります。

AdMob の設定や App Store 向けのビルドと違って、キャッシュ掃除は成果が見えにくい地味な作業です。だからこそ雑になりやすく、事故もそこで起きます。

ドライランを既定にした — 書き直したスクリプトと実行結果

規則を言葉にしたところで、実行するのは疲れた深夜の自分です。読まなくても安全な側に倒れる作りにしておかないと、たぶん同じことを繰り返します。

そこで掃除スクリプトを書き直しました。既定はドライラン、実行するときだけ環境変数で明示する形です。

#!/usr/bin/env bash
set -Eeuo pipefail
 
DRY_RUN="${DRY_RUN:-1}"              # 既定はドライラン。消すときだけ DRY_RUN=0
ROOT="${1:?ROOT を指定してください}"   # 未定義も空文字も、ここで落ちる
 
total_kb=0
while IFS= read -r cache; do
  : "${cache:?キャッシュパスが空です}"   # ループの中でも都度検証する
  case "$cache" in
    /|/*/) echo "refuse: $cache(ルート直下は対象外)" >&2; continue ;;
  esac
  kb=$(du -sk "$cache" | cut -f1)
  total_kb=$((total_kb + kb))
  printf '%-28s %8s KB\n' "$cache" "$kb"
  [ "$DRY_RUN" = "0" ] && rm -rf -- "$cache"
done < <(find "$ROOT" -maxdepth 2 -type d -name build-cache | sort)
 
echo "----"
echo "対象 ${total_kb} KB / DRY_RUN=${DRY_RUN}"

検証用に、キャッシュを持つリポジトリ二つと、構成変更でキャッシュが無くなったリポジトリ一つを作って走らせました。既定のドライランでは、こう出ます。

/tmp/guardtest/demo/repoA/build-cache    12292 KB
/tmp/guardtest/demo/repoC/build-cache     7172 KB
----
対象 19464 KB / DRY_RUN=1

キャッシュを持たない repoB は一覧に現れません。消す前に「何が対象で、合計どれだけか」が数字で見えます。

引数を渡し忘れた場合と、空文字を渡した場合も試しました。どちらも同じ場所で止まり、終了コードは 1 でした。

./clean.sh: line 5: 1: ROOT を指定してください

そのうえで DRY_RUN=0 を付けて実行すると、一覧に出ていた二つだけが消え、repoB のディレクトリは触られないまま残りました。ドライランで見た内容と、実際に起きたことが一致しています。この一致を目で確かめられることが、私にとっての安心の中身でした。

一点、書きながら踏んだ落とし穴を残しておきます。最初は find ... | while read とパイプでつないでいたのですが、合計が最後まで 0 のままでした。

パイプ版 total=0
プロセス置換版 total=19464

パイプの右側は別のシェルとして動くため、ループの中で足した total_kb が外に戻ってきません。done < <(find ...) のプロセス置換に変えると、期待どおりの合計になりました。合計を出す種類のスクリプトでは、静かに間違うので気をつけたいところです。

追記(2026年8月) — 既定になる前に確かめておくこと

この記事を書いたあと、auto モードは試用の位置づけから前へ進み、2026年8月14日に Pro・Max・Team で既定有効になると案内されました。手で止めていた工程が、これからは既定で流れていくことになります。

Anthropic は既定化の説明の中で、Claude Code の権限プロンプトのうち 97% が承認されている、と述べています。同社自身の集計なので数字の扱いには慎重でありたいのですが、この一点は身に覚えがありました。あの夜より前の私も、表示された確認をほとんど読まずに通していたはずです。

読まずに承認する確認は、実質的に防御ではありません。そう考えると、既定化は「守りが薄くなる変更」というより、機能していなかった守りが正直な形に置き換わる変更なのだと思います。

既定が切り替わる前に、私は次の三つを手元で確かめました。

確かめたことやり方
止まる操作と進む操作の境界削除・force push・外部への書き込みを、捨ててよいリポジトリで実際に走らせて記録する
自分の環境固有の危険な手順止まってほしいのに進んでしまった手順を洗い出し、拒否ルールとして書き出す
スクリプト側の防御が生きているか本記事のドライランと ${VAR:?} を、掃除以外の手順にも展開する

三つ目が、私にとっては一番効きました。auto モードが止めてくれるのは、値の裏づけが取れない操作です。裏づけは取れているけれど自分の意図とは違う、という間違いは、エージェント側からは正しい操作に見えます。そこは自分の側で塞ぐしかありません。

これから取り組むこと

ドライランは、掃除以外の手順にも順に広げているところです。移行スクリプトやログの整理など、「一覧を先に出せる作業」であれば同じ形が使えます。

残っている課題は、拒否ルールの粒度です。広く書けば止まりすぎて読まなくなり、狭く書けば抜けが出ます。しばらくは実際に止まった回数と、そのうち本当に危なかった回数を記録して、手元の数字で調整していこうと考えています。

賢いエージェントに任せられる範囲は、確かに広がりました。同時に、任せる側が「どこで立ち止まってほしいか」を先に決めておく責任も、静かに増している気がします。

あの夜、冷たくなった手のことは、しばらく忘れないと思います。削除の前に一呼吸置いてくれた事前確認に、素直に感謝しています。同じように夜間へ作業を委ねている方の、小さな備えの参考になれば幸いです。お読みいただき、ありがとうございました。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-07-19
auto モードの設定が、いつの間にか自分でも思い出せなくなっていた — 既定へ戻す claude auto-mode reset の使いどころ
夜間の自動運用を続けるうちに、auto モードの設定を少しずつ触り足していました。ある朝の違和感で、自分が何を変えたのか思い出せないことに気づきます。既定へ戻す claude auto-mode reset を基点にして設定を組み直した、個人開発の片付けの記録です。
Claude Code2026-08-10
同じ rm -rf が、10箇所では戻せて5箇所では戻せませんでした — auto モード既定化の前に可逆性を測る
8月14日から auto モードが Pro / Max / Team の既定になります。止まる境界は「取り消せない・破壊的・環境の外」ですが、可逆性は操作の名前ではなく実行時点の状態で決まりました。復旧不能バイトを数えるプローブと、15対象の実測をまとめます。
Claude Code2026-06-14
課金変更の前夜に、headless 実行の消費を1週間だけ計測した記録
6/15 から headless Claude Code が月次クレジットへ移るのを前に、自分の無人実行が実際に何トークン消費しているかを1週間ログに残し、どのプランで足りるかを数字で判断した手順をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →