Claude Code や Google Apps Script で毎朝の集計や問い合わせの仕分けを自動化したあと、必ず起きるのが「いつの間にか止まっていた」です。API の一時的なエラー、権限の拒否、利用上限、スクリプトの実行時間切れ。どれも音を立てずに止まり、気づくのは数日後の「あのレポート、来てなくない?」です。
この記事では、Claude Code と Apps Script の公式ドキュメント(2026年10月時点)だけを出典に、無人で動く自動化を「止まっていないと言い切れる」状態にするための最小セットを整理します。実行の記録・失敗の通知・傾向の集計・再実行の決め方の4段階と、週次点検のチェックリストを用意しました。読者は、社内の業務改善・情報システム・Web の担当者を想定しています。
結論 — 先に要点だけ
- 「動いた」と「できた」を分けて記録する。 起動したか、途中で止まったか、完走したが成果物が無いか、は別の失敗です。終了コードだけでは最後の一つが分かりません
- 記録の最小セットは JSON 出力+終了コード。
claude -p --output-format jsonが返すsession_id・total_cost_usd・permission_denialsを毎回ファイルに残し、cron のラッパーで終了コードを判定します - 通知はフックで仕組みにする。 API エラーで止まった
StopFailure、ツールの失敗PostToolUseFailure、終了時のSessionEndを settings に書けば、人が見張らなくても知らせが届きます - 傾向は OpenTelemetry で集める。 コスト・トークン・API エラー・ツールの成否がメトリクスとイベントで出ます。プロンプト本文は既定で送られません
- 再実行は「同じ結果になる設計」が前提。 途中で止まったジョブの続きは保証されないので、処理済みを飛ばす作りにしてから再実行します
「動いた」と「できた」を分ける — 失敗の4分類
自動化の失敗は、どこで止まったかで気づき方も対処も違います。最初に自社のジョブがどの失敗を起こしうるかを整理すると、記録すべき項目が決まります。
| 分類 | 何が起きているか | 気づける手がかり | 典型的な原因 |
|---|---|---|---|
| 起動しなかった | プロセスが立ち上がらない | cron のログ、ラッパーの終了コード | 認証切れ、環境変数の欠落、実行時間帯のサーバー停止 |
| 途中で止まった | 実行中に API やツールのエラーで終了 | 終了コード(0 以外)、StopFailure フック | レート制限、過負荷、利用上限、権限の拒否 |
| 完走したが未達 | 終了コードは 0 でも成果物が無い・空 | 成果物の有無・件数の確認、JSON の result | 対象データが空、許可されていない操作を静かに諦めた |
| 完走して余計なことをした | 意図しない書き込みや送信 | 書き込み先の変更履歴、permission_denials の逆(許可しすぎ) | 許可リストが広すぎる、プロンプトの指示不足 |
Claude Code は成功時に終了コード 0、失敗時に 0 以外を返すので、スクリプトはこの値で分岐できます。ただし、認証の欠落のように実行の内側で起きた失敗は、標準出力に結果として印字されます。終了コードだけを見て「動いた」と判断すると、3番目と4番目の失敗を見逃します。
※ 出典: Claude Code Docs — Run Claude Code programmatically(取得 2026-10)
クラウドの Routines を使っている場合も同じです。公式ドキュメントは、実行一覧の緑色の状態を「セッションが基盤側のエラーなしに開始・終了した」印であり、「プロンプトの仕事が成功した意味ではない」と明記しています。ネットワークの遮断、接続先ツールの欠落、仕事そのものの失敗は、実行を開いて書き起こしを読まないと分かりません。
※ 出典: Claude Code Docs — Automate work with routines(取得 2026-10)
層1 — 実行の記録を残す(JSON 出力と終了コード)
claude -p の出力形式は text(既定)・json・stream-json の3つです。無人実行では json を選び、標準出力を丸ごと日付付きのファイルに保存します。応答の本文は result に、セッションを特定する session_id と、費用の推定値 total_cost_usd(モデル別の内訳付き)が同じ JSON に入ります。
| 記録したい項目 | 取り出し方 | 使い道 |
|---|---|---|
| 仕事の結果 | JSON の result | 成果物が空でないかの確認 |
| セッション ID | session_id | 失敗時に --resume で続きを調べる |
| 費用の推定 | total_cost_usd | 日次の合計と急増の検知 |
| 拒否された操作 | 結果メッセージの permission_denials | 「静かに諦めた」操作の発見 |
| 終了の仕方 | シェルの終了コード | 0 以外なら通知 |
| 決まった形の出力 | --json-schema と structured_output | 件数・ステータスを機械で読む |
total_cost_usd はクライアント側の推定で、実際の請求額とは差が出ます。--continue や --resume で過去の会話を続けた場合は、それまでの実行分も含めた会話全体の合計が報告される点にも注意が必要です。
※ 出典: Claude Code Docs — Run Claude Code programmatically(取得 2026-10)
無人実行で人が答えられない確認は、--permission-prompts none を付けると拒否に倒れ、Claude に「再試行しないこと」が伝わります。拒否された要求は stream-json では permission_denied のシステムメッセージとして流れ、最後の結果メッセージの permission_denials に一覧で残ります。この一覧が毎日同じ操作で埋まるなら、それは「許可リストに足すか、仕事から外すか」を決める材料です。
--max-turns は上限に達するとエラーで終了し、--max-budget-usd は API 呼び出しの支出が上限に達した時点で止まり、以後のサブエージェントの生成も失敗します。どちらも「止まった理由」がはっきりする終わり方なので、終了コードと合わせて記録すれば、翌朝に原因を追えます。
※ 出典: Claude Code Docs — CLI reference(取得 2026-10)
記録の雛形 — cron のラッパー
次のシェルスクリプトは、JSON をファイルに残し、終了コードで分岐する最小の形です。通知の送り先(notify の中身)は、自社で使うチャットやメールのコマンドに置き換えてください。
#!/bin/bash
# nightly-report.sh — 毎朝の集計ジョブのラッパー
set -u
LOGDIR="$HOME/automation-logs"
STAMP="$(date +%Y%m%d-%H%M)"
OUT="$LOGDIR/report-$STAMP.json"
mkdir -p "$LOGDIR"
notify() { logger -t nightly-report "$1"; } # 社内の通知コマンドに置き換える
timeout 20m claude --bare -p "$(cat "$HOME/prompts/nightly-report.md")" \
--allowedTools "Read,Bash(python3 scripts/aggregate.py *)" \
--permission-mode dontAsk --permission-prompts none \
--max-turns 30 --max-budget-usd 2.00 \
--output-format json > "$OUT"
CODE=$?
if [ "$CODE" -ne 0 ]; then
notify "失敗: 終了コード $CODE($OUT)"; exit "$CODE"
fi
if [ ! -s "$HOME/reports/daily-$(date +%F).md" ]; then
notify "完走したが成果物が無い($OUT)"; exit 10
fi
要点は3つです。timeout で時間の上限を切る、終了コードが 0 でも成果物の有無を別に確かめる、JSON を日付付きで残す。成果物の確認を入れるだけで、「完走したが未達」を翌日ではなく当日に拾えます。
プロセス監視ツールから SIGTERM で止めた場合、Claude Code は終了コード 143 で終わり、進行中のターンは未完のまま結果は記録されません。ラッパーの timeout が発動したときも同じ扱いになるので、143 は「時間切れで打ち切った」印として通知文に含めておくと、後の調査が楽です。
※ 出典: Claude Code Docs — Run Claude Code programmatically(取得 2026-10)
層2 — 失敗を通知する(フックを仕組みにする)
フックは Claude Code のライフサイクルの決まった時点で自動的に実行されるコマンドで、settings.json に宣言します。監視に使うのは次の4つです。
| フック | いつ動くか | 監視での使い道 | 補足 |
|---|---|---|---|
StopFailure | ターンが API エラーで終わったとき | 止まった理由を通知する | マッチャーでエラー種別を絞れる(rate_limit、overloaded、authentication_failed、billing_error、server_error など) |
PostToolUseFailure | ツールの呼び出しが失敗したとき | 特定コマンドの失敗を記録する | マッチャーはツール名(Bash、Edit、mcp__.* など) |
SessionEnd | セッションが終了するとき | 実行の要約を保存する | 全フック合計で 1.5 秒の予算。個別の timeout を長くすると最大 60 秒まで延びる |
Notification | Claude Code が通知を出すとき | 権限確認や入力待ちの発生を記録する | マッチャーは通知種別(permission_prompt、idle_prompt など) |
※ 出典: Claude Code Docs — Hooks reference(取得 2026-10)
StopFailure のマッチャーは英数字と _、区切りの | だけを受け付けます。複数のエラー種別をまとめて拾うなら rate_limit|overloaded|server_error のように書きます。コマンド型フックの既定のタイムアウトは 600 秒で、超えるとフックは取り消され、出力は捨てられます。
通知フックの雛形
API エラーで止まったときとツールが失敗したときに、社内の通知コマンドを呼ぶ最小構成です。--bare で起動するジョブはフォルダの settings.json を読まないので、--settings で明示的に渡します。
{
"hooks": {
"StopFailure": [
{
"matcher": "rate_limit|overloaded|server_error|billing_error|authentication_failed",
"hooks": [
{ "type": "command", "command": "$HOME/hooks/notify-failure.sh" }
]
}
],
"PostToolUseFailure": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "$HOME/hooks/log-tool-failure.sh" }
]
}
]
}
}
フックのスクリプトは標準入力から JSON を受け取ります。共通の入力には session_id・hook_event_name・cwd・permission_mode・transcript_path が含まれるので、通知文にセッション ID と書き起こしのパスを入れておけば、翌朝そのまま調査に入れます。
#!/bin/bash
# notify-failure.sh — StopFailure フックから呼ばれる
input=$(cat)
sid=$(jq -r '.session_id' <<<"$input")
ev=$(jq -r '.hook_event_name' <<<"$input")
path=$(jq -r '.transcript_path' <<<"$input")
echo "[$(date)] $ev session=$sid transcript=$path" >> "$HOME/automation-logs/failures.log"
logger -t claude-automation "$ev session=$sid" # 社内の通知コマンドに置き換える
exit 0
フックの終了コードには意味があります。0 は成功、2 は「その操作を止める」で、1 やそれ以外は「止めない失敗」として処理が進みます。通知や記録が目的のフックは、失敗しても本体を止めないよう 0 で終えるのが基本です。
※ 出典: Claude Code Docs — Hooks reference(取得 2026-10)
社内でこの記録・通知の仕組みまで含めて自分たちで組む場合の進め方は、企業向けの有料の実務書にもまとめています。
層3 — 傾向を集める(OpenTelemetry)
「昨日は動いたか」の次に必要なのが「先週から API エラーが増えていないか」「費用が増えていないか」です。Claude Code は OpenTelemetry(OTel)でメトリクスとイベントを外部に出せます。環境変数 CLAUDE_CODE_ENABLE_TELEMETRY=1 で有効にし、OTEL_METRICS_EXPORTER と OTEL_LOGS_EXPORTER に otlp などの送り先を指定します。
| 種類 | 名前 | 監視での使い道 |
|---|---|---|
| メトリクス | claude_code.cost.usage | 日次の費用の推移、急増の検知 |
| メトリクス | claude_code.token.usage | トークン量の推移 |
| メトリクス | claude_code.session.count | ジョブが毎日起動しているかの確認 |
| イベント | claude_code.api_error | エラーの種類・ステータス・試行回数 |
| イベント | claude_code.api_retries_exhausted | 再試行を使い切って失敗した回数 |
| イベント | claude_code.tool_result | ツールごとの成功可否と所要時間 |
| イベント | claude_code.tool_decision | 許可・拒否の判断と、その出どころ(設定・フック・ユーザー) |
プロンプト本文と応答本文は既定では送られず、OTEL_LOG_USER_PROMPTS=1 や OTEL_LOG_ASSISTANT_RESPONSES=1 を明示したときだけ含まれます。Bash のコマンド内容やファイルパスも既定では <REDACTED> で、OTEL_LOG_TOOL_DETAILS=1 を付けない限り出ません。監視目的なら、まず既定のまま件数と費用と成否だけを集めれば足ります。
送り先を開発者が勝手に変えられないようにするには、管理設定(managed settings)で OTEL_EXPORTER_OTLP_* を固定します。
※ 出典: Claude Code Docs — Monitoring(取得 2026-10)
OTel の設定は、Team・Enterprise の分析ダッシュボード、Console の利用状況ページ、クラウド事業者の請求画面のどれを使っていても共通に使えます。公式ドキュメントは、ユーザーごとのトークンと費用をほぼリアルタイムで自社の監視基盤に流せる唯一の選択肢としています。
※ 出典: Claude Code Docs — Manage costs effectively(取得 2026-10)
Apps Script 側の最小セット — 失敗メール・実行一覧・割り当て
問い合わせの仕分けや Gmail のラベル付けを Apps Script で組んでいる会社も多いはずです。Apps Script には監視の仕組みが最初から3つあり、まずそれを使い切ります。
失敗の通知メール。 時間主導トリガーが失敗すると、Apps Script は Google のシステム送信元から「Summary of failures for Apps Script」という件名のメールを送ります。本文には失敗の要約と、トリガーを無効化・再設定するリンクが入ります。通知はアクティブなトリガーに付随する機能で、トリガーが有効な間は頻度だけを変えられ、止めるにはトリガー自体を無効化または削除します。
実行一覧。 通知メールのリンクからプロジェクトを開き、左のナビゲーションの「実行数(Executions)」を開くと、どの実行が失敗したかとエラーメッセージが並びます。また、時間主導トリガーの時刻は少しずらされ、たとえば午前9時の繰り返しトリガーは 9時から10時の間のどこかで固定されます。「9時に来ない」は失敗ではありません。
※ 出典: Google Apps Script — Installable Triggers(取得 2026-10)
ログの置き場所。 エディタの「実行ログ」は開発中の確認用で、長くは残りません。長期に残すなら Cloud Logging で、Apps Script のダッシュボードから簡易表示を、標準の Cloud プロジェクトを紐づければ Google Cloud コンソールから全機能を使えます。例外を Cloud Error Reporting に集約するには、プロジェクト設定で「未処理の例外を Cloud Operations に記録する」を有効にします。
※ 出典: Google Apps Script — Logging(取得 2026-10)
止まる原因として多いのが割り当て(quota)の超過です。主なものを表にまとめます。
※ 出典: Google Apps Script — Quotas for Google Services(取得 2026-10)
| 項目 | 一般アカウント | Google Workspace アカウント |
|---|---|---|
| スクリプトの実行時間 | 6 分 / 実行 | 6 分 / 実行 |
| トリガーの合計実行時間 | 90 分 / 日 | 6 時間 / 日 |
| メールの宛先数 | 100 / 日 | 1,500 / 日 |
| URL Fetch の呼び出し | 20,000 / 日 | 100,000 / 日 |
| 同時実行 | 30 / ユーザー | 30 / ユーザー |
※ 出典: Google Apps Script — Quotas for Google Services(取得 2026-10)
1回の実行が 6 分を超えると途中で打ち切られます。件数が増えると突然この壁に当たるので、処理件数を実行ごとに区切り、続きを次のトリガーに回す設計にしておきます。Claude の API を URL Fetch で呼ぶ構成では、1日の呼び出し回数の上限にも注意が必要です。
やり直しの最小セット — 再実行の決め方
通知が届いたあとに困るのが「もう一度動かしてよいか」です。判断の順番を決めておくと、担当者が変わっても同じ対応になります。
- 原因の種類を見る。
StopFailureのマッチャーやapi_retryイベントのerrorに出るエラー種別で分けます。rate_limit・overloaded・server_errorは時間を置いて再実行、authentication_failed・billing_error・account_on_holdは設定や契約を直すまで再実行しない - どこまで終わったかを確かめる。 成果物の有無、書き込み先の変更履歴、JSON の
resultを見ます。途中まで書き込まれた成果物があれば、再実行で上書きしてよいかを先に決める - 続きから再開するか、最初からやり直すかを選ぶ。
--resumeにsession_idを渡せば同じ会話の続きに入れますが、費用の合計は会話全体で報告されます。SIGTERM で止めた実行は、既定では中断したターンをそのままにして次のプロンプトが会話を進めます。中断したターンの続きを自動で再開させるには、環境変数CLAUDE_CODE_RESUME_INTERRUPTED_TURNを1に設定します - 再実行は1回だけ。 2回目も失敗したら、自動の再実行を止めて人が見ます。再試行の回数を決めずに cron に任せると、同じ失敗で費用だけが積み上がります
※ 出典: Claude Code Docs — Run Claude Code programmatically(取得 2026-10)
API の一時的なエラーについては、Claude Code 自身が再試行します。stream-json では再試行のたびに system/api_retry イベントが出て、attempt(試行回数)、retry_delay_ms(次の試行までの待ち時間)、error(rate_limit、overloaded、server_error などの種別)が記録されます。ラッパー側で同じ再試行を重ねる必要はなく、使い切って失敗したときにだけ再実行を検討します。
Apps Script のトリガーは失敗しても次回の予定時刻にまた動くので、再実行を組む必要はありません。代わりに「前回の続き」を Script Properties などに残し、同じメールを二度処理しない作りにしておきます。
週次点検チェックリスト(12項目)
毎週決まった曜日に、担当者が印刷して確認できる形にしています。
- 先週の実行日ごとに JSON ファイルが残っている(欠けた日があれば「起動しなかった」)
- 終了コード 0 以外の実行が何件あり、それぞれの原因が分かっている
- 成果物(レポート・シート・ラベル)が毎日生成されていて、空の日が無い
-
permission_denialsに毎日同じ操作が出ていない(出ていれば許可リストか仕事の見直し) -
total_cost_usdの日次合計が先週と比べて急増していない -
StopFailureフックの通知が、届くべき人に届く経路になっている(テスト送信済み) - フックのスクリプトが 0 で終わり、本体を止めていない
- OTel の
claude_code.api_errorが増えていない - Apps Script の失敗通知メールが担当者の受信箱で埋もれていない(フィルタで振り分け済み)
- Apps Script の実行一覧に失敗が並んでいない
- Apps Script の実行時間が 6 分の上限に近づいていない
- 認証情報(API キー・トークン)の期限と、担当者の異動が反映されている
※ 出典: Google Apps Script — Quotas for Google Services(取得 2026-10)
よくある失敗パターン 5つ
1. 終了コードだけで「成功」にしている。 対象データが空でも、権限が無くて操作を諦めても、終了コードは 0 になり得ます。成果物の有無を別に確かめる1行が無いと、この失敗は数日気づかれません。
2. 通知先が個人のメールだけ。 担当者が休みの日、失敗メールは誰も読みません。共有の受信箱かチャットの共通チャンネルに送り、Apps Script の失敗メールはフィルタで目立つラベルを付けておきます。
3. フックが本体を止めている。 通知スクリプトの中で失敗して終了コード 2 を返すと、フックの種類によっては本体の操作が止まります。記録・通知用のフックは常に 0 で終える設計にします。
4. 再実行を cron に任せて無限に繰り返す。 認証切れや契約上の停止は、何度再実行しても直りません。再実行は1回だけ、2回目の失敗は人に回す、と決めておきます。
5. 監視のために本文まで全部ログに残している。 OTel の既定はプロンプトも応答も送らない設定です。監視には件数・費用・成否で足りるので、本文を残すのは社内のデータ取り扱いルールで必要と判断したときだけにします。
公式ドキュメント・リソース集
- Run Claude Code programmatically —
-pの出力形式・終了コード・SIGTERM・再開 - CLI reference —
--max-turns、--max-budget-usd、--permission-prompts、--debug-file - Hooks reference — イベント一覧・入出力・終了コード・タイムアウト
- Monitoring — OpenTelemetry のメトリクス・イベント・既定の秘匿設定
- Manage costs effectively — 組織ごとの費用の見え方と上限の置き場所
- Automate work with routines — 実行一覧の見方と緑色の状態の意味
- Apps Script — Installable Triggers — 失敗通知メールと実行一覧
- Apps Script — Logging — 実行ログと Cloud Logging
- Apps Script — Quotas — 実行時間・トリガー・メールの割り当て
よくある質問
Q. クラウドの Routines の実行一覧が緑色なら、仕事は成功したと考えてよいですか?
いいえ。公式ドキュメントは、緑色の状態を「セッションが基盤側のエラーなしに開始・終了した」印であり、プロンプトの仕事が成功した意味ではないと明記しています。ネットワークの遮断や接続先ツールの欠落、仕事そのものの失敗は、実行を開いて書き起こしを読んで初めて分かります。CLI からは /schedule に「今朝の実行はなぜ何もしなかったのか」と聞けば、最近の実行とその状態、ログの要約を返してくれます。
Q. 失敗の通知はメールで十分ですか?
Apps Script の失敗通知はメールだけなので、まずはそれで足ります。ただし通知は「エラーで終わった」ことしか知らせません。「完走したが仕事は未達」はメールでは分からないので、成果物の有無を別の仕組みで確かめる必要があります。Claude Code 側はフックで任意のコマンドを呼べるため、チャットや監視ツールへ送る形にも広げられます。
Q. プロンプトや社内データの中身を、監視のためにログへ残しても大丈夫ですか?
Claude Code の OpenTelemetry 出力は、プロンプト本文・応答本文・ツールの引数や出力を既定では送らず、明示的に環境変数で有効にした場合だけ含めます。まずは既定のまま件数・コスト・成功可否だけを集め、本文が必要になった段階で、社内のデータ取り扱いルールと照らして判断するのが安全です。全社の生成 AI 利用ルールの作り方は生成 AI の社内利用ガイドラインの作り方で扱っています。
Q. 止まった自動化を再実行するとき、同じ処理が二重に走りませんか?
二重に走る可能性はあります。ジョブが途中で止まったとき、どこまで終わったかは Claude Code の側では保証されません。再実行しても同じ結果になる設計(既に処理済みの行は飛ばす、成果物を上書きしない)にしておくか、人が確認してから再実行する運用にするのが基本です。
次の一歩
まず、いま動いている自動化を1本選び、上のラッパーの形に「成果物の有無の確認」と「終了コードの通知」の2行を足してください。それだけで「完走したが未達」を当日に拾えます。1週間分の JSON がたまったら、週次点検チェックリストを一度通し、permission_denials と total_cost_usd を見て、許可リストと上限額を見直します。
どの自動化から監視を足すべきか、通知の経路を社内の体制にどう合わせるかから相談したい場合は、お問い合わせから現在の状況をお知らせください。契約前提ではありません。Claude 導入支援の全体像はClaude 導入支援ハブに、既にある Claude Code の運用が安全かを確かめる無料の診断はハーネス健全度診断にまとめています。
更新履歴
- 2026-10-01: 初版公開