概要
Claude Codeで判断ルールの外部化(指示ファイル化)や作業の自動化(スクリプト・フック化)を1年ほど積み上げてきました。あるとき「この積み上げの先に、本当に解決したい問題があるのか」をAI自身に聞いてみたところ、痛いところを突かれました。
要約すると、積み上げてきた自動化の根っこにある課題は「作業が多いから自動化する」ではなく、次の2点だったということです。
- 判断ルールが「書いただけ」で止まっていて、新しい判断が入るたびに更新されるループが回っていない
- 自動化が静かに壊れていても気づく仕組みがない
この記事では、特に2番目の「壊れたことに気づけない自動化」を、どう検知・検証するかについて書きます。
「動いているはず」が一番危険
自動化されたタスク(定期実行されるスクリプトやフック)の怖いところは、失敗したときにサイレントに止まることです。実際、「毎回自動更新されるはずのファイル」が、確認したら1ヶ月前から更新が止まっていたことがありました。エラーログも通知も出ておらず、気づいたきっかけは自分がたまたまファイルの更新日時を見たことだけでした。
これは典型的な「自動化を検証する自動化がない」状態です。自動化した処理そのものは動いていても、「その処理が正しく最後まで実行されたか」を確認する仕組みが別途必要になります。
対処1: 最終実行時刻を記録し、期待される間隔と比較する
一番シンプルなのは、自動化対象の処理が完了するたびにタイムスタンプを記録し、それを別のチェック処理で検証する方法です。
#!/bin/bash
# update_task.sh: 本来の自動化タスクの末尾に追加する
TASK_NAME="daily_report"
STATE_FILE="$HOME/.local/state/automation_heartbeat.json"
python3 - "$TASK_NAME" "$STATE_FILE" <<'EOF'
import json, sys, time
from pathlib import Path
task, state_path = sys.argv[1], Path(sys.argv[2])
state = json.loads(state_path.read_text()) if state_path.exists() else {}
state[task] = int(time.time())
state_path.write_text(json.dumps(state))
EOF
そして、この記録を定期的に見に行く別のチェックスクリプトを用意します。
#!/bin/bash
# check_heartbeat.sh: 別のタイミング(cronやフック)で実行する監視役
STATE_FILE="$HOME/.local/state/automation_heartbeat.json"
MAX_AGE_HOURS=26 # 日次タスクなら24時間+バッファ
python3 - "$STATE_FILE" "$MAX_AGE_HOURS" <<'EOF'
import json, sys, time
from pathlib import Path
state_path, max_age_hours = Path(sys.argv[1]), float(sys.argv[2])
state = json.loads(state_path.read_text()) if state_path.exists() else {}
now = time.time()
for task, last_run in state.items():
age_hours = (now - last_run) / 3600
if age_hours > max_age_hours:
print(f"[WARN] {task} は {age_hours:.1f} 時間更新されていません")
EOF
重要なのは、実行する仕組みそのものと、それを見張る仕組みを分けることです。同じスクリプトの中に監視ロジックを混ぜると、そのスクリプト自体が動かなくなったときに監視も一緒に止まってしまいます。
対処2: 権限的な安全装置と、監視対象の分離
Claude Codeに環境の安全チェックを任せる場合、AIの操作範囲を安全な範囲に制限する仕切り(サンドボックスや許可リストの仕組み)自体が壊れていないかも監視対象になります。ここで気をつけたいのが、監視の基準を書き換える操作自体を安全装置がブロックするケースがあることです。
たとえば「今の状態を正しい状態として記録し直す」操作は、見方を変えれば「監視の基準そのものを書き換える操作」でもあります。AI自身の安全装置がこれを検知して自動的に止めるのは妥当な挙動ですが、結果として最後の1コマンドは人間が手元で直接実行する必要が出てきます。
これは設計上の欠陥ではなく、意図した安全性とのトレードオフです。「AIが見つけるところまで」と「人が実行するところまで」を最初から分けて考えておくと、ブロックされたときに慌てずに済みます。
対処3: 「直した」の確認は、副作用まで見る
自動化の別の失敗パターンとして、直したはずの処理が実は途中で止まっていた、というケースもありました。設定ファイルを1つ書き換えた影響で、実行前に確認を求めるプロンプトが1つ挟まるようになり、それより後に続くはずだった一連の処理が丸ごと巻き添えで止まっていた、というものです。
「実行した」というログや報告だけを見ると成功に見えても、その後続処理の副作用(この場合はバックアップ先のファイルが実際に更新されているか)まで確認しないと、静かな失敗を見逃します。
# 「実行完了ログがある」だけでなく、副作用の結果を検証する
if [ "$(find backup_dir -newer state_file -type f | wc -l)" -eq 0 ]; then
echo "[WARN] バックアップの副作用が確認できません"
fi
自動化の検証は、「処理が呼ばれたか」ではなく「期待した結果が実際に生まれたか」を見る必要があります。
まとめ
- 自動化が壊れる一番危険なパターンは、エラーも通知もなくサイレントに止まることです。実行するスクリプトとは別に、最終実行時刻を記録・検証する仕組みを用意すると早期に気づけます
- 監視・検証の仕組みは、監視対象のスクリプトと物理的に分離しておく。同じプロセスに混ぜると、対象が壊れたときに監視も道連れで止まります
- AIの安全装置が監視基準の書き換えそのものをブロックするケースがある。「AIが見つけるところまで」と「人が実行する最後の一手」を最初から分けて設計しておくと、ブロックされたときの対応がスムーズになります
- 「実行された」というログだけでなく、期待した副作用(ファイルの更新、データの反映など)が実際に発生しているかまで確認して初めて「直った」と言えます