定期タスクが開発ツリーを直接叩いて古いコードで動き続けるのを検出して直す
毎晩動いているはずのバッチが数十コミット前のコードで走り、結果は毎回exit 0。専用クローン+同期ラッパへ張り替え、失敗注入と時間帯ゲートの罠まで含めて検証する手順。
約3.6万トークンの節約 (API料金換算で約54円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「定期タスクが開発ツリーを直接叩いて古いコードで動き続けるのを検出して直す」は、業務自動化カテゴリのAI指示書(MDファイル)です。毎晩動いているはずのバッチが数十コミット前のコードで走り、結果は毎回exit 0。専用クローン+同期ラッパへ張り替え、失敗注入と時間帯ゲートの罠まで含めて検証する手順。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.6万トークン(API料金換算で約54円)・86%のトークンを節約できます。
- カテゴリ
- 業務自動化
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.2万トークン
- この巻物使用時
- 約6,000トークン
- 節約量
- 約3.6万トークン (約54円)
- 更新日
- 2026-08-31
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-b4c9bc71/raw を読み込んで、この指示書どおりに実装して"
中身
定期タスクが「開発ツリー」を直接叩いていて、何ヶ月も古いコードで動いているのを見つけて直す
毎晩動いているはずのバッチが、実は数十コミット前のコードで走り続けている——しかも タスクスケジューラの結果は毎回「0(正常)」。この記事は、その状態を検出して恒久的に潰す手順です。
対象: Windows タスクスケジューラ / cron から自動スクリプトを回している環境。 AI エージェント(Claude Code 等)にそのまま読ませて実行させられる粒度で書いています。
1. 何が起きているのか
多くのプロジェクトで、定期タスクはこう登録されています。
powershell.exe -File "<開発ツリー>\tools\nightly-batch.ps1"
<開発ツリー> は人間や AI が日常的に作業しているクローンです。ここが罠になります。
- 誰かが検証ブランチを
checkoutしたまま放置すると、その日以降ずっとそのブランチのコードが夜間に走る。 git pull --ff-onlyを回す同期処理を入れていても、そのブランチの上流に対して成功するので 「更新しました」と報告しながら main の修正は一生届かない。- 追加した新しいステップは、そのツリーに存在しないので実行されない。 それでもスクリプトは最後まで走り、exit 0 を返す。
実例: あるマシンで夜間バッチが feat/...(既にクローズされた PR のブランチ)に停まっており、
origin/main から 91 コミット遅れ。数週間前に追加したステップは一度も実行されていなかった。
LastTaskResult はずっと 0 だった。
2. 検出する(3コマンド)
2-1. どの定期タスクが開発ツリーを指しているか
Get-ScheduledTask | Where-Object {
$_.Actions.Arguments -match '<開発ツリーのパスの一部>' -or
$_.Actions.Execute -match '<開発ツリーのパスの一部>'
} | ForEach-Object {
'{0,-32} {1}' -f $_.TaskName, (($_.Actions | ForEach-Object { $_.Arguments }) -join ' ')
}
cron なら crontab -l | grep <開発ツリーのパスの一部>。
2-2. そのツリーがどれだけ遅れているか
git -C <開発ツリー> rev-parse --abbrev-ref HEAD # main 以外なら赤信号
git -C <開発ツリー> fetch origin main -q
git -C <開発ツリー> rev-list --count HEAD..origin/main # 0 以外なら遅れている
2-3. 「新しいステップが本当に無い」ことを目で見る
遅れの数字だけでは実害が伝わりません。main にしか無いステップ名を grep して 0 件を確認します。 この 0 件が「夜間に一度も実行されていない」の決定的な証拠になり、同時に修理後の合否判定にも使えます。
grep -c '<main にしか無いステップ名>' <開発ツリー>/tools/nightly-batch.ps1 # → 0
grep -c '<main にしか無いステップ名>' <専用クローン>/tools/nightly-batch.ps1 # → 1 以上
3. 直す — 「専用クローン + 同期ラッパ」に張り替える
開発ツリーを main に戻すのは解決になりません。開発が続く限り翌日にはまた遅れます。 恒久解は「定期タスク専用のクリーンなクローンを作り、毎回 origin/main へ同期してから実行する」ことです。
3-1. 同期ラッパ
nightly-bootstrap.ps1(要点のみ。実運用ではログ出力を必ず付ける):
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$Target,
[Parameter(ValueFromRemainingArguments=$true)][object[]]$TargetArguments
)
$repo = if ($env:NIGHTLY_REPO) { $env:NIGHTLY_REPO } else { Join-Path $HOME '.cache\nightly-repo' }
$repoUrl = '<リポジトリのURL>'
try {
if (-not (Test-Path (Join-Path $repo '.git'))) {
git clone --branch main -- $repoUrl $repo
} else {
git -C $repo fetch origin main
git -C $repo reset --hard origin/main
git -C $repo clean -qfd
}
Write-Log 'リポ同期' ('ok:origin/main ' + (git -C $repo rev-parse --short HEAD))
} catch {
# ★ 同期に失敗しても中断しない。夜間の仕事を同期の失敗で落とさない
Write-Log 'リポ同期' ('warn:' + $_.Exception.Message + ' 既存版で続行')
}
$targetPath = if ([IO.Path]::IsPathRooted($Target)) { $Target } else { Join-Path $repo $Target }
if (-not (Test-Path -LiteralPath $targetPath -PathType Leaf)) {
Write-Log '対象確認' ("error:対象が見つからない " + $targetPath); exit 1 # ★ 異常は exit 1
}
& powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File $targetPath @TargetArguments
$code = $LASTEXITCODE
Write-Log '対象実行' ("ok:" + [IO.Path]::GetFileName($targetPath) + " 終了コード=" + $code)
exit $code # ★ 対象の終了コードをそのまま返す。後片付けの警告で塗り潰さない
設計上の要点は4つです。
- 同期失敗は警告どまり(
warn:既存版で続行)。同期のためにその夜の仕事を落とさない。 - 対象が無い/対象が失敗したら、その終了コードで exit する。全パス exit 0 は監視を無意味にします。
- 相対パスで対象を受ける(
-Target tools\nightly-batch.ps1)。絶対パスを埋め込むと結局ツリーに固定される。 - ラッパ自身の自己更新を入れると、ラッパの修正も自動で行き渡ります (同期後に専用クローン側のラッパと自分のハッシュを比べ、違えば自分を上書きする)。
3-2. 呼び出し先の「リポの探し方」も直す(最大の罠)
これを忘れると、専用クローンから起動しても中で開発ツリーへ戻ります。
バッチ本体が子スクリプトを $HOME/<リポ名>/tools/xxx.mjs のように探していないか確認し、
候補の先頭に「自分自身のリポ」を差し込みます。
$candidates = @(
(Split-Path -Parent $PSScriptRoot), # ★ 自分が置かれているリポを最優先
(Join-Path $HOME '<リポ名>') # 従来のフォールバックは残す
)
3-3. タスクを張り替える(バックアップ必須)
# 1) 戻せるようにする
New-Item -ItemType Directory -Path "$HOME\.task-backups" -Force | Out-Null
Export-ScheduledTask -TaskName '<タスク名>' |
Set-Content -LiteralPath "$HOME\.task-backups\<タスク名>.xml" -Encoding UTF8
# 2) Action だけを差し替える(トリガーと実行アカウントは保持される)
$arg = '-NoProfile -NonInteractive -ExecutionPolicy Bypass ' +
'-File "<専用クローン>\tools\nightly-bootstrap.ps1" -Target tools\nightly-batch.ps1'
Set-ScheduledTask -TaskName '<タスク名>' -Action (
New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $arg
)
# 3) 読み返して確認する(設定したつもりで終わらせない)
(Get-ScheduledTask -TaskName '<タスク名>').Actions | ForEach-Object { $_.Arguments }
戻すときは Register-ScheduledTask -Xml (Get-Content <xml> -Raw) -TaskName <タスク名> -Force。
4. 検証する — ここが本題
4-1. 正常系だけを見ても、この型のバグは絶対に出ない
「手動実行したら正常終了しました」は何も確かめていません。必ず失敗を注入します。
# A: 存在しない対象 → exit 1 とログの error 行を期待
powershell -File <ラッパ> -Target 'tools\no-such-file.ps1'; $LASTEXITCODE # → 1
# B: わざと exit 3 を返すスクリプトを対象にする → 3 が伝播することを期待
'exit 3' | Set-Content .\fail-probe.ps1
powershell -File <ラッパ> -Target (Resolve-Path .\fail-probe.ps1); $LASTEXITCODE # → 3
B が 0 になるなら、ラッパが後片付けや Write-Warning で終了コードを塗り潰しています。
その状態では本番の失敗が永久に「正常」として記録されます。
4-2. 「時間帯ゲート」に騙されない
夜間バッチは「深夜料金の時間帯だけ動く」ような時間帯ガードを持っていることがよくあります。
if (-not $offPeak) { Write-Log '時間帯判定' 'skip:帯域外'; exit 0 }
この場合、日中に手動実行すると数秒で exit 0 して本体を一切実行しません。 これを「正常に動いた」と読むのも「壊れている」と読むのも誤りです。実際にやってしまいがちな誤読です。
- 手動実行が想定より桁違いに速く終わったら、まずゲートを疑う
(
grep -nE 'off-peak|時間帯|Hour -' <script>)。 - 日中に確かめられるのはラッパ層まで(同期・対象解決・終了コード伝播)。そこは 4-1 の方法で確実に確かめる。
- 本体まで含めた確認は、帯の中の実走を待つ。待つと決めたら
「どのログのどの行が出れば合格か」を1行だけ書き残す(例:
<main にしか無いステップ名> / ok)。
4-3. 合否は「新しいステップのログ行」で判定する
翌朝、次の2つを見ます。
grep 'リポ同期' <ログ>/nightly-bootstrap-<日付>.log # ok:origin/main <sha>
grep '<main にしか無いステップ名>' <ログ>/nightly-batch-<日付>.log # ok
2行目は旧ツリーの版には存在しないステップなので、出た時点で配線が効いた決定的な証拠になります。 「遅れが 0 になった」ではなく「新しい仕事が実際に走った」で判定するのがポイントです。
5. 同じ壊れ方を二度と作らないために
- インストーラ/セットアップスクリプトを直す。タスクを登録している箇所が
-File "<リポ>\tools\nightly-batch.ps1"のままだと、新しいマシンすべてに同じ地雷が配られます。 登録は必ずラッパ経由(-File "<専用クローン>\tools\nightly-bootstrap.ps1" -Target tools\<対象>)にする。 - 棚卸しを定期化する。2-1 のコマンドを月次で回し、開発ツリーを指すタスクが 0 件であることを確認する。
- スキップと成功を区別してログに書く。
skip:とok:とerror:を別語にしておくと、 後から grep で「本当に動いた夜」だけを数えられます。 - 1台直しても終わりではない。同じ環境に同型のタスクが複数あるのが普通です(実例では 7 本中 1 本を直した時点で まだ 6 本残っていた)。2-1 の棚卸しコマンドを流して残数を必ず数えてから完了と報告する。
6. AI エージェントに丸ごと投げるときの指示文
このマシンの定期タスクのうち、開発用クローンを直接実行しているものを洗い出して、
専用クローン + 同期ラッパ経由へ張り替えてください。手順:
1) タスク棚卸し(開発ツリーのパスを含む Action を列挙)
2) そのツリーのブランチと origin/main からの遅れコミット数を出す
3) main にしか無いステップ名を grep して 0 件であることを示す(=実害の証拠)
4) Export-ScheduledTask で XML バックアップを取ってから Action を張り替え、読み返して確認
5) 失敗を注入して検証(存在しない対象→exit 1 / exit 3 を返す対象→exit 3 が伝播)
6) 本体に時間帯ゲートがあるか確認し、あれば日中実行で何がスキップされたかまで報告する
7) 残っている同型タスクの本数を数えて報告する
完了報告には「手動実行して正常終了」とだけ書かないこと。
よくある質問
+「定期タスクが開発ツリーを直接叩いて古いコードで動き続けるのを検出して直す」とは何ですか?
毎晩動いているはずのバッチが数十コミット前のコードで走り、結果は毎回exit 0。専用クローン+同期ラッパへ張り替え、失敗注入と時間帯ゲートの罠まで含めて検証する手順。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.2万トークンかかりますが、この巻物を使えば約6,000トークンで済みます。差し引き約3.6万トークン(API料金換算で約54円)・86%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
Google Meet 自動参加&動画配信Bot 開発指示書
指定した時刻に Google Meet へ自動参加し、動画を再生しながら画面共有する Bot を、Claude Code に一発で作らせる開発指示 MD。朝会の定例動画配信・ウェビナーの自動放送に。
受信メール添付を案件フォルダへ自動取込するパイプライン
メールを読むアプリとドライブに書くアプリが別、という現実的な構成で顧客メールの添付を案件フォルダへ無人保存する設計。権限追加を避ける理由、実行時間制限下の予算3本立て、二重の重複防止、base64url/行数上限/変換判定などの実装罠、案件と顧客のマッチング、名寄せは候補提示+人の承認にする型まで。
Gmail 自動仕分け&返信ドラフト生成MD
受信メールを AI が分類 (要返信/情報/営業/スパム) してラベル付けし、要返信メールには返信ドラフトまで自動生成する仕組みを作らせる指示書。DWD (ドメイン全体委任) 設定手順込み。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア