Claude Code をタスクスケジューラから claude -p で毎日動かしています。ランチャー(起動用の PowerShell スクリプト)には「終了コードが 0 以外なら通知を出す」という見張りを付けていました。
ところがある朝、ルーティンの中の X 予約投稿が失敗していたのに、通知は鳴りませんでした。終了コードは 0 でした。この記事は、そのときに入れた対策のメモです。
何が起きたか
- ウィンドウを出さない設定で Chrome 操作をさせていたため、日時ピッカーが描画されず予約日時を入力できなかった
- Claude は手順を止め、報告に「予約に失敗した」と書いて終了した
- 終了コードは 0。ランチャーの見張りは何も言わなかった
- 気づいたのは、開きっぱなしのブラウザタブを見たときだった
終了コードが答えているのは「AI が最後まで動いたか」
考えてみると当然でした。claude -p のプロセスとしての仕事は「指示を受け取り、返事を書き終えること」です。失敗したことを返事に書いた時点で、プロセスは正常終了します。0 以外になるのは、プロセス自体が落ちた・強制終了されたときです。
| 知りたいこと | 終了コードで分かるか |
|---|---|
| エージェントが最後まで動いたか | 分かる |
| 頼んだ手順が成功したか | 分からない(失敗しても 0) |
人が書くスクリプトなら失敗箇所で exit 1 すれば揃いますが、エージェントは「失敗しました」と文章で書いてそのまま正常終了します。
別のパターンとして、本体の返事のあとに裏で走る処理の待ち時間上限に引っかかった回も、成果物ファイルが無いまま 0 で終わっていました。
出力全文から「失敗」「エラー」を grep する案はボツ
正常な報告にもこれらの語は普通に出てきます。
・リンク切れ: 異常なし
・前回のエラーは再発していない
これを拾うと毎日誤報が鳴り、そのうち誰も通知を見なくなります。書き方を縛るより、判定に使う場所を 1 か所に決めて、そこだけ決まった形で書かせるほうが確実です。
報告の最終行に状態行を書かせる
スキル(手順書)の報告節に次を追加しました。
報告の最後の行に、次のどちらかを1行だけ書く:
ROUTINE-STATUS: OK … すべての手順が成功した、または予定どおりスキップした
ROUTINE-STATUS: ALERT … 1つでも失敗した手順がある
決めたポイントは 3 つです。
- 普通の文章に出てこない形にする(英大文字+コロン)
- 二択にする。「要確認」のような中間を作ると AI がそこへ逃げる
- 予定どおりのスキップは OK に入れる。新着が無くて何もしなかった日に毎回 ALERT が出るのを防ぐ
ランチャー側の判定
終了コードの判定は残したまま、0 のときだけ状態行を見ます。
$output = & claude -p "/my-routine" 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
Send-Alert "終了コード $exitCode で失敗"
}
else {
$status = @($output | Where-Object { $_ -match '^\s*ROUTINE-STATUS:' }) |
Select-Object -Last 1
if ($status -match '^\s*ROUTINE-STATUS:\s*ALERT\s*$') {
Send-Alert "処理は最後まで動いたが、一部が失敗している"
}
}
最初は「出力の最後の 1 行」だけを見ていましたが、レビューで直しました。
- 状態行のあとに空行や締めの一言が付くことがある
- 報告の途中で「状態行は ROUTINE-STATUS: ALERT になる」のように説明として同じ文字列を書くことがある
なので「行頭が ROUTINE-STATUS: の行のうち最後のもの」を拾い、^ と $ で ALERT ちょうどかを確かめています。Send-Alert は環境に合わせて置き換えてください。通知本文はログの場所と一言だけにしています。
状態行が無いケースと、成果物チェック
穴は「状態行を書き忘れたら検知できない」ことです。今は対応済みのルーティンが一部なので「状態行が無ければ何もしない」にしていますが、全部対応したら状態行が無いこと自体を ALERT にする予定です。
もう一つ、毎朝のレポートのように成功すれば必ずファイルができるルーティンでは「今日の日付のファイルがあるか」も確認しています。待ち時間上限で止められたケースは報告を書く前に止まるので、状態行には出てきません。
結果、見張りは 3 段になりました。
| 見るもの | 拾える失敗 |
|---|---|
| 終了コードが 0 以外 | エージェント自体が最後まで動かなかった |
| 状態行が ALERT | 最後まで動いたが、中の手順が失敗した |
| 成果物ファイルが無い | 報告すら書けずに止まった |
通知を出すのはランチャーだけ
「失敗したら AI 自身に通知させればいい」という案もありましたが採りませんでした。終了コードが 0 以外になる失敗では AI は通知を送れないので、結局ランチャーも見張ることになります。通知の出どころが 2 か所になると、鳴らなかったときにどちらの見落としか追いにくい。エージェントは状態を書くだけ、知らせるのはランチャーだけに分けています。
まとめ
-
claude -pの終了コードは「最後まで動いたか」しか答えない。手順の失敗は 0 で返る - 出力全文の grep は誤検知する。最終行付近の決まった形の 1 行だけを機械が読む
- 予定どおりのスキップは OK 扱いにする
- 成果物ファイルの有無も併せて見る
- 通知の出どころはランチャー 1 か所にする
人が読む報告と、機械が読む 1 行を、同じ返事の中で分けておくのがコツでした。
この記事は、Claude Code に書かせている日記ブログ「クジラとAIと」の記事をもとに、運用している私(クジラ)が書き直したものです。
元記事: https://kujiragames.com/2026/10/routine-status-last-line/