Claude Codeの定期実行——launchdで36本を毎日動かして分かった落とし穴
Claude Codeの定期実行とは、対話画面を開かずに「1回だけ動いて終わる実行」をOSの時計から自動で起動する使い方です。 macOSならlaunchd(マックに最初から入っている、時間が来たらプログラムを動かす仕組み)、Linuxならcronで叩きます。私たちはこの方式で36本のジョブを毎日走らせ、記事・動画・SNS投稿・計測をほぼ人手なしで回しています。この記事では最小の設定に加えて、設定が終わったあとに必ずぶつかる4つの壊れ方を、27日ぶんの実測ログとあわせて公開します。
Claude Codeの定期実行とは何をすることか
やっていることは驚くほど単純です。claude -p "やってほしいこと" という1回きりのコマンドを、時計に叩かせるだけです。
-p(--print)は対話モードに入らず、プロンプトを1回処理して終了するオプションです(CLIリファレンス)。人の返事を待たないので、寝ている間も動きます。
なお Claude Code には公式のスケジュール実行機能(スケジュールに従ってプロンプトを実行する)もあります。本記事は「自分のMacで、自前のシェルスクリプトを毎日走らせたい」場合の構成です。
最小構成——毎朝1回、Macで自動起動する
- やることを1本のシェルスクリプトにまとめる(先頭で必ず作業フォルダへ
cdする) - その中から
claude -p "プロンプト"を、使ってよい道具を絞って呼ぶ - launchd の設定ファイル(plist)に起動時刻を書く
launchctl bootstrapで登録し、ログファイルで結果を確かめる
シェル側は、実際に私たちが使っている形だとこうなります。
#!/bin/zsh
set -u
export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/bin:/bin"
cd "$HOME/Side/JurisCodeAI" # ← これが無いとファイル操作系のツールが軒並み拒否される
claude -p "$PROMPT" \
--permission-mode acceptEdits \
--allowedTools "Read" "Glob" "Grep" "Edit" "Write" "WebSearch" \
"Bash(pnpm*)" "Bash(git add*)" "Bash(git commit*)" "Bash(git push*)" \
>> "$LOG" 2>&1最初の2行が地味に効きます。launchd から起動されたプロセスはログイン時のシェル設定を読みません。ターミナルでは動くのに定期実行だと command not found になる原因は、ほとんどがこの PATH 未設定です。
cd も同じくらい重要です。作業フォルダに移らないまま起動すると、現在地がルート(/)になり、ファイルの読み書きが許可範囲外として弾かれます。
plist(launchd の設定ファイル)は、時刻の指定だけならこれで足ります。
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/you/scripts/blog-drip.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>8</integer>
<key>Minute</key><integer>10</integer>
</dict>書式の詳細は launchd.plist のマニュアル が正確です。
なぜセッションの中のスケジュールでなくlaunchdなのか
以前、私たちは日次の改善ループをClaude Codeのセッション内スケジュールに載せていました。結果、ターミナルを閉じた瞬間に全部消えました。改善と週次レビューが止まっていたことに、数日気づきませんでした。
この一件以降、「定期実行はlaunchdだけを正とする」を運用の鉄則にしています。セッション内のスケジュールは、あくまで対話中の一時的な補助と割り切っています。
全体の構成をどう組んでいるかは Claude Codeで個人開発を完全自動化する構成 にまとめています。
設定より難しいのは「動かし続ける」こと
定期実行は、動かすまでが1日、動かし続けるのが数か月です。私たちが実際に踏んだ壊れ方は、次の4つに集約されました。
| 落とし穴 | 何が起きるか | 対処 |
|---|---|---|
| 二重起動 | 同じジョブが並走し、同じ投稿やコミットが2回出る | スクリプト先頭でPIDロック |
| 利用上限 | その日の実行が丸ごと失われる | 上限を検出してキューに積み、後で叩き直す |
| 権限リストの漏れ | エラーを出さず「何もせず成功」する | 実績のある許可リストをコピーして削る |
| 無言の失敗 | 終了コードが0のまま中身が間違っている | 成果物そのものを検査する |
二重起動——実行時間が再実行の間隔をまたぐと必ず重なる
2026-08-03、週次の計測ジョブが2本同時に走りました。未実行を拾う見張り役が30分ごとに巡回するのに、そのジョブ自体が30分以上かかっていたためです。
実行時間が再実行の間隔をまたぐジョブは、いつか必ず二重起動します。 対処は数行で済みます。
LOCK="$OUT/blog-drip.pid"
if [[ -f "$LOCK" ]] && kill -0 "$(cat "$LOCK")" 2>/dev/null; then exit 0; fi
echo $$ > "$LOCK"
trap 'rm -f "$LOCK"' EXIT INT TERM自分のプロセスIDをファイルに置き、生きていたら黙って降りるだけです。trap を付けておくと、途中で落ちてもロックが残りません。
利用上限——モデルを変えても回避できない
ここは私たちが一番高い授業料を払った箇所です。利用上限はアカウント全体の枠なので、別のモデルに切り替えても回避できません。 当初は「上限なら次のモデルへ」という仕組みだけを持っており、全部が同じ枠を共有していることに気づくのが遅れました。
さらに、2026-08-06には週次の上限に当たって13本のエンジンが同時に止まりました。検出の条件が session limit という文字列しか見ておらず、実際に返ってきた weekly limit に一致していなかったのが原因です。
エラー文言での判定は、想像で書くと必ず取りこぼします。実際の文言を1度自分の目で見てから条件を書くのが、結局いちばん速い道でした。
現在は上限を検出したらジョブ名をキューに記録し、30分ごとの番人が解除後に launchctl kickstart で丸ごと叩き直します。各ジョブに「もう作ってあるならスキップ」のガードを入れてあるので、重複実行は安全です。
権限リストの漏れ——一番静かに壊れる
--allowedTools に必要な道具を書き忘れると、エージェントはエラーを出しません。使える範囲だけで作業して、成功として終わります。 ログは正常、成果物はゼロ。この空振りが最も見つけにくい壊れ方でした。
対処は単純で、うまく動いているジョブの許可リストを丸ごとコピーして、要らないものを削る方式に統一しました。ゼロから書き起こすと、必ず何かが抜けます。
無言の失敗——終了コード0を信用しない
上の3つに共通するのは、「失敗したのに成功として記録される」という性質です。異常終了はログに残り次の実行で気づけますが、無言の失敗は下流の工程がそれを前提に進むぶん傷が深くなります。この検査の作り方は AI自動化の無言の失敗を検知する設計 に詳しくまとめています。
27日ぶんのログが示したこと
2026-07-19から2026-08-14までの、自社のモデル切り替えログ364行を集計した実測値です。
- モデルの切り替えが発生した回数: 166回
- 全モデルが上限で実行できなかった回数: 67回
- 再実行キューに積まれたジョブ: 45件
- そのうち人手なしで完了まで到達したもの: 27件
上限に当たる回数そのものは、こちらの設計では減らせません。ですが当たったあとに自動で取り返せるかどうかは設計で決まります。実際この記事を書いた日も、朝9時すぎにブログ生成のジョブが上限で落ち、再実行キューに積まれていました。
定期実行の価値は「人がいない時間にも進むこと」です。だからこそ、人がいない時間に静かに壊れる経路を先に塞ぐほうが、機能を増やすより効きます。
よくある質問
Q. cronではなくlaunchdを使うべきですか
macOSで自分のMacを使うなら、launchdのほうが無難です。スリープや再起動をまたいだ挙動が扱いやすく、launchctl kickstart で手動の叩き直しができます。Linuxサーバーで動かすならcronで問題ありません。
Q. Macがスリープしていても実行されますか
されないことがあります。launchdは電源が入っていてもスリープ中は起動を遅らせ、復帰後にまとめて実行する挙動を取ります。時刻の正確さが要るジョブは、電源接続とスリープ設定を先に確認してください。
Q. --allowedTools はどこまで絞るべきですか
「そのジョブが実際に使う道具だけ」が原則です。ただし絞りすぎると、前述のとおりエラーも出ずに空振りします。動いている類似ジョブの設定をコピーして不要分を削り、初回は必ずログで成果物の有無を確認するのが安全です。
Q. 定期実行が失敗したことに、どうやって気づけばいいですか
終了コードだけを見る監視では気づけません。「ジョブが動いたか」と「成果物が正しく出たか」は別の問いなので、後者を別の仕組みで検査してください。私たちは公開物の実在確認を別ジョブに分け、当日中に答え合わせをしています。
Q. 1日に何本くらいのジョブが現実的ですか
本数より、失敗したときに自動で取り返せる設計かどうかが効きます。私たちは36本(2026-08-07時点の棚卸し)を運用していますが、増やすたびに二重起動と上限の当たりやすさが上がるため、1本追加するごとにロックと再実行の経路を必ず用意しています。
コメント
#Claude Code#AI開発#自動化#個人開発