はじめに:自動化は「動いた日」ではなく「動き続けた日数」で評価する
Claude Codeで定期実行を組むと、その日は動きます。問題はその先です。自動化は壊れるとき、エラーを出さずに黙って止まることがあります。
先日、筆者が運用しているブログの自動投稿がまさにこれでした。「毎日1本公開する」設定を組み、初日は正常に公開。ところが次に気づいたときには、25日間で公開された記事は0本。エラー通知は一度も来ていませんでした。スケジュールの設定画面上は「有効」のままです。
この記事では、その原因と、同じ事故を二度と起こさないための「沈黙を監視する仕組み」を、コピペで動く形で共有します。定期実行を1つでも動かしている方には、そのまま使える内容です。
対象は、Claude Codeで定期実行・自動化を組んでいる(または組みたい)開発者、個人事業主、中小企業のご担当者です。
なぜ「エラーが出ずに止まる」のか:3つの典型パターン
今回の調査と、これまでの運用で遭遇した停止原因は、次の3つに整理できます。
パターン1:実行基盤がそもそも起動していない
今回の原因はこれでした。アプリ内蔵のスケジュール機能は、アプリが起動している間だけ動くものがあります。アプリを閉じている時間帯に実行予定時刻が来ると、その日は単に飛びます。設定は「有効」のままなので、画面を見ても異常に見えません。
対策は、OS常駐の仕組み(macOSならlaunchd、Linuxならcron/systemd timer)に移すことです。こちらはアプリの起動状態に依存しません。
パターン2:プロセスがハングして居座る
ネットワーク断などでタイムアウトの無い通信が固まると、プロセスが終了しません。多くのスケジューラは「前回のプロセスが生きている間は次回を起動しない」ため、1回のハングが翌日以降を丸ごとブロックします。筆者は別の自動化で、これにより7日間の停止を経験しました。
対策は、実行スクリプト側にタイムアウト(ウォッチドッグ)を持たせることです。
パターン3:途中で人間の承認待ちになる
自動実行の途中で権限確認のプロンプトが出ると、誰も応答せず止まります。バックグラウンド実行でも、権限確認はメイン側に出て待ちになります。
対策は、自動実行では使うツールを事前に明示しておくこと、そして「完了したか」を実行結果ではなく成果物で判定することです。
手順1:まず現状を診断する(/doctor)
2026年7月のアップデートで、/doctor(別名 /checkup)が追加されました。設定まわりの健康診断を行い、問題を検出して修正まで提案してくれます。自動化が動かないときの一次切り分けに向いています。
Claude Codeを起動して、次を入力します。
/doctor
期待できる結果:インストール状態、設定ファイル、MCPサーバー、権限まわりの診断結果が一覧で表示されます。/ 確認:問題があれば該当項目に指摘が出ます。ここで異常が無ければ、原因は環境側ではなく「実行されていない(パターン1)」を疑います。
なお、カスタマイズが原因かを切り分けたいときは、すべての設定を無効にして起動する --safe-mode も使えます。
手順2(この記事の目玉):「沈黙」を監視する仕組みを作る
ここからが本題です。多くの人は「失敗したら通知する」監視を作りますが、今回のような事故では失敗すら発生しません。プロセスが動いていないので、失敗通知も出ないのです。
そこで監視すべきは成否ではなく、「最後に成果物が出てから何日経ったか」という沈黙の長さです。以下は筆者が実際に運用しているものを、そのまま使える形にしたスクリプトです。
healthcheck.sh(コピペでそのまま動きます)
#!/bin/bash
# 自動化が「静かに止まっていないか」を、最後の成果物からの経過日数で検知する。
set -uo pipefail
TARGET_DIR="${1:-$HOME/your-output-dir}" # 成果物が日付名で入るディレクトリ
MAX_SILENT_DAYS="${MAX_SILENT_DAYS:-2}" # 何日空いたら異常とみなすか
# 最新の成果物(YYYY-MM-DD 形式のディレクトリ)を探す
# 注: $(ls) は使わない。パスにスペースがあると単語分割で壊れる
latest=""
for d in "$TARGET_DIR"/2*/; do
[ -d "$d" ] && latest="$(basename "$d")"
done
if [ -z "$latest" ]; then
echo "[異常] 成果物が1つも見つかりません"
exit 1
fi
days=$(python3 - "$latest" <<'PY'
import sys
from datetime import date
y, m, d = map(int, sys.argv[1].split("-"))
print((date.today() - date(y, m, d)).days)
PY
)
if [ "$days" -gt "$MAX_SILENT_DAYS" ]; then
echo "[異常] 最終実行は $latest ($days 日前)。しきい値 $MAX_SILENT_DAYS 日超"
exit 1
fi
echo "[正常] 最終実行 $latest ($days 日前)"
使い方と期待できる結果:
chmod +x healthcheck.sh
./healthcheck.sh ~/your-output-dir
正常なら [正常] 最終実行 2026-08-01 (0 日前)、停止していれば [異常] 最終実行は 2026-07-07 (25 日前)... と出て終了コード1を返します。筆者が今回作って最初に実行したとき、まさに後者の「25日前」が表示され、停止を初めて数値で確認できました。
このスクリプトを、監視したい自動化とは別のスケジュールで毎日走らせます。同じ仕組みに相乗りさせると、その仕組みごと止まったときに監視も一緒に止まるためです。
手順3:実行スクリプト側に必ず入れる2つの保険
パターン2(ハング)への対策として、実行スクリプトには次の2つを入れます。どちらも実際に事故ってから追加したものです。
保険1:自前のタイムアウト
macOSには標準で timeout コマンドがありません。そのため自前で用意します。
run_with_timeout() {
local secs="$1"; shift
set -m
"$@" &
local pid=$!
(
deadline=$(( $(date +%s) + secs ))
while kill -0 "$pid" 2>/dev/null; do
# ⚠️ sleep での経過管理は不可。macOSのスリープ中はカウントが止まる
[ "$(date +%s)" -ge "$deadline" ] && { kill -- -"$pid" 2>/dev/null; break; }
sleep 10
done
) &
local wpid=$!
wait "$pid" 2>/dev/null; local rc=$?
kill "$wpid" 2>/dev/null; wait "$wpid" 2>/dev/null
set +m
return "$rc"
}
確認:わざと run_with_timeout 5 sleep 60 を実行し、終了コード143(強制終了)で戻れば機能しています。監視ループが10秒間隔のため、打ち切りは指定より最大10秒遅れます(筆者がループを1秒間隔にして試したときは、ちょうど5秒で打ち切られました)。
保険2:終了コードではなく成果物で成否を判定する
プロセスが「正常終了」しても、肝心の成果物ができていないことがあります。最後に必ず実物を確認します。
if [ -f "$OUT_DIR/$(date +%Y-%m-%d)/result.json" ]; then
echo "✅ 成功"
else
echo "❌ 成果物が無い(終了コードは正常でも失敗扱い)"
exit 1
fi
そのまま使えるプロンプト
A. 自分の自動化が止まっていないか点検してもらう
このプロジェクトで定期実行している仕組みを洗い出し、それぞれについて「最後に成果物が出た日付」と「今日までの経過日数」を表にしてください。3日以上空いているものがあれば、原因の候補を挙げてください。修正はまだしないでください。
確認:経過日数の表が出て、放置されていた仕組みが特定できれば成功。
B. 沈黙監視をプロジェクトに組み込んでもらう
このプロジェクトの定期実行について、成否ではなく「最後に成果物が出てからの経過日数」を監視するヘルスチェックを作ってください。しきい値は2日、超えたら終了コード1と復旧手順を出力すること。監視対象とは別のスケジュールで動かす前提にしてください。
確認:単体で実行でき、正常時と異常時で終了コードが変わることを確認できれば成功。
C. 既存スクリプトにウォッチドッグを追加してもらう
このスクリプトに、タイムアウト付き実行の仕組みを追加してください。macOSには timeout コマンドが無いこと、システムスリープ中は sleep のカウントが止まるため経過時間は date による壁時計で判定することを前提にしてください。追加後、意図的にタイムアウトさせる検証コマンドも教えてください。
確認:検証コマンドを実行し、指定秒数で打ち切られれば成功。
D. 環境まわりの一次切り分け
/doctor
確認:診断結果が一覧表示される。異常が無ければ、環境ではなく「そもそも起動していない」方向で原因を探ります。
E. 事故の再発防止をルール化する
今回の停止事故(原因:実行基盤がアプリ起動中しか動かず、25日間気づかなかった)を踏まえ、このプロジェクトの運用ルールに追記すべき項目を3つ提案してください。抽象的な心構えではなく、確認コマンドや実行頻度まで含めた具体的な運用手順にしてください。
確認:コマンド付きの手順として書かれていれば成功。
つまずき所(実際にはまった点)
- パスにスペースがあると壊れる。
for d in $(ls -d "$DIR"/2*/)は、パスに空白が含まれると単語分割され、存在しないディレクトリを見に行きます(筆者の環境では実際にこれで最初の実行が失敗しました)。上のスクリプトのように、$(ls)を使わずglobで回すのが安全です。 sleepはスリープ中カウントが止まる。Macが眠っている間、sleepの経過時間は進みません。タイムアウト判定は必ずdate +%sの壁時計で行います。- 「有効」表示は「動いている」ではありません。設定画面の状態や最終実行の記録は、実際に成果物が出たかを保証しません。判定は必ず成果物で行ってください。
- 監視を同じ仕組みに相乗りさせない。本体が止まると監視も止まり、二重に気づけなくなります。
今日の実務での使いどころ(15分)
まず、いま動かしている定期実行を1つ選び、最後に成果物が出た日付を確認してください。これだけで、止まっているのに気づいていない仕組みが見つかることがあります。次に上の healthcheck.sh をコピーし、しきい値2日で1回実行する。ここまでで15分です。
自動化は「作った日」ではなく「動き続けた日数」で価値が決まります。沈黙を測る仕組みを1つ持っておくと、次の25日を失わずに済みます。
※本記事の機能情報は2026年8月1日時点の公式ドキュメント・リリースノートに基づきます。仕様は変わることがあるため、最新情報は一次情報をご確認ください。


コメント