0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeを無人で自律改善させる ― コストで暴走を止めるautopilot

0
Posted at

「Claude Code環境」シリーズの第8弾です。会話ログを長期記憶に変える話で無人ジョブを紹介しましたが、今回はその親玉 ―― ユーザー入力ゼロでClaude Codeに自分の環境を改善させ続けるautopilotの話です。

「自律ループ」と言うと聞こえはいいですが、無人でLLMを回すと2つこわいことが起きます。①プラン枠を食い潰す②同じタスクを延々と繰り返す。実際どちらも踏みました。この記事は、その2つをどう機械で止めたかの記録です。

全体像:毎朝1 Phaseだけ進める

launchdから毎朝5:00に起動して、claude -p のヘッドレスで「改善タスクを1つ拾って、1 Phaseだけ進めて終わる」を繰り返します。

  • 対象は ~/.claude/ 配下だけ(個人プロジェクトやVaultの個人情報には触らせない)
  • dry(プロンプト生成のみ)/ apply / once の3モード
  • 走らせる前にコスト枠をチェックし、枠が危なければ即skip

無人で「賢いことを少しずつ」やらせるのが狙いで、1回で大改造はさせません。

暴走対策1:コスト枠で先に止める

最初のゲートはコストです。5時間ブロックの出力トークンを見て、危険水位なら走る前に止めます。

BUDGET=$(~/.claude/scripts/token-budget-advisor.sh --short)
if echo "$BUDGET" | grep -qE '🔴|critical|cap-near'; then
  log "ABORT: budget critical"; exit 0
fi

ただラベル判定だけだと穴がありました。🟡burst 表示のまま実際の残量がマイナス、というケースが素通りして、残量−8003で重いモデルが606秒走ったことがあります。なのでラベルとは別に、残量を数値で再計算して0以下なら実行しません。

REMAINING=$((800000 - BLOCK_OUT))    # 5h block cap 800k 想定
if [ "$REMAINING" -le 0 ]; then
  log "SKIP: block exhausted"; exit 0
fi

コスト上限は「ラベル」ではなく「残量の数値」で持つべきでした。色や文字列のしきい値判定は、境界で必ずすり抜けます。最後は引き算で <= 0 を見るのが確実です。

さらに残量に応じて effort と max-turns を可変にします。残りが少なければ軽量・少ターン、余裕があれば高めに。無人ジョブの既定モデルは安価なものにしています(高性能モデルの常用で5hブロックを食い潰し、以降の全スロットがSKIPになった事故の反省)。重いタスクを意図的に回すときだけ環境変数で上書きします。

MODEL="${AUTOPILOT_MODEL:-claude-sonnet-4-6}"   # 既定は安価モデル

ターン数だけでは止まらないので、壁時計のtimeoutも被せます。max-turnsはターン数しか縛らず、7.25時間走った実績があったため、gtimeout 7200(2h)で頭打ちにします。

暴走対策2:同じタスクを繰り返させない

これがいちばん効いた修正です。タスク候補を next-session-todo.md の「High impact」セクションから拾うのですが、最初のawkが壊れていて候補が常に空でした。

# 旧実装の範囲パターン /^### High impact/,/^###/ は
# 開始行自身が終端条件にも一致して即終了 → 常に空。
# → フォールバックの固定タスクが毎回選ばれ、同一タスクを6日で17回反復。

候補が空だとフォールバックの固定タスクが毎回選ばれ、同じタスクを6日間で17回やっていました。範囲パターンをフラグ方式に直して候補を正しく列挙し、さらに履歴ベースのdedupeを足しました。

  • 直近48hに exit 0 で完了済みのタスクはskip
  • 直近2回連続で失敗しているタスクもskip(無理なものを叩き続けない)
if any(r.get("exit_code") == 0 for r in recent):
    print("done-recently")          # 最近やった → 次の候補へ
if len(recent) >= 2 and all(r["exit_code"] != 0 for r in recent[-2:]):
    print("failing-repeatedly")     # 連続失敗 → 諦めて次へ

履歴は1行1レコードのJSONLで持ち、タスク名・exit code・所要秒・モデル・effortを記録します。これで「最近やった/詰まり続けている」を機械で判定できます。

自己検証:AIの自己申告を実測で照合する

無人で回すと、claude -p の「N MB回収しました」という自己申告を誰も検証しない問題が出ます。そこでharness側で実測を取り、結果ファイルに並記します。

DISK_BEFORE_KB=$(du -sk "$HOME/.claude" | awk '{print $1}')
# ...claude -p 実行...
DISK_AFTER_KB=$(du -sk "$HOME/.claude" | awk '{print $1}')
DISK_DELTA_KB=$(( DISK_AFTER_KB - DISK_BEFORE_KB ))
FILES_TOUCHED=$(find "$HOME/.claude" ... -newer "$RUNSTART_REF" | wc -l)

結果ファイルの末尾に「## 自己検証(harness実測 / claudeの主張ではない)」として disk delta と変更ファイル数を書き、「本文の数値主張がこの実測と乖離する場合は本文を疑う」と添えます。AIに語らせた数字と、OSが計った数字を必ず並べる。これが無人運用の信頼性の肝でした。

監視:ステータスラインにプラン枠を出す

暴走を止めるには、人間側もコストを常時見たい。Claude Codeのステータスラインに、5h/7dのプラン使用率を出しています。嬉しいのは、これがstdinから直接取れること。認証もエンドポイント呼び出しも不要です。

H5=$(j '.rate_limits.five_hour.used_percentage')
H5R=$(j '.rate_limits.five_hour.resets_at')
D7=$(j '.rate_limits.seven_day.used_percentage')
CTX=$(j '.context_window.used_percentage')

rate_limits は「サブスクで最初のAPI応答後にだけ現れる」ので、初回ターンまでは -- にフォールバックします。これで「🕐 5h 42% ⏪14:30 / 📅 7d 18%」のように、プラン枠とリセット時刻が常に見えます。autopilotが裏で食った分も、ここに即反映されます。

踏んだ落とし穴

  • ラベル判定だけで残量マイナスが素通り → 残量を数値で再計算し <= 0 で止める
  • max-turnsだけでは7時間走るgtimeout で壁時計cap
  • 高性能モデル常用で枠を食い潰し全SKIP → 無人既定は安価モデル、重い時だけ上書き
  • awkの範囲パターンが空で固定タスクを17回反復 → フラグ方式+履歴dedupe
  • AIの自己申告を誰も検証しない → harnessで実測し結果に並記
  • launchdの最小PATHでclaudeが見つからない → PATH→.local/bin→nvmの順でフォールバック

まとめ

  • 無人ループはコスト枠を数値で先にチェックしてから走らせる(ラベル判定は境界で漏れる)
  • 暴走は残量cap・壁時計timeout・安価モデル既定の三重で止める
  • 同タスク反復は履歴JSONLのdedupe(最近完了/連続失敗をskip)で潰す
  • AIの自己申告は必ずharness実測と並記して、盛り・誤読を検出可能にする
  • プラン枠はstatuslineのstdinから取れる。常時見える化が監視の土台

ここまでの8本で、記憶・スキル・コンテキスト・launchd・協業・セキュリティ・長期記憶・自律ループと、私のClaude Code環境のほぼ全体を書きました。読んでくれてありがとうございました。


Lily@bokuwalily)― 個人開発者。Claude Code で自動化基盤を組みながら、iOSアプリやWebサービスを量産しています

皆さんの ❤️ やシェアが励みになります!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?