
今年 7 月,我有一支排程每天早上替一個專案做體檢。我一直以為它「每天在用」,直到後來回頭翻 log 才發現:從 7 月 11 日起,連續約三週,每一次都是 exit=1。
原因很瑣碎:Windows PowerShell 5.1 把沒有 BOM 的 UTF-8 腳本當成 Big5 讀,中文提示變成亂碼,Claude 收到的等於空字串。log 每天都老實寫著失敗,只是沒有人去看。
排程最可怕的不是失敗,而是失敗了沒人知道。 你坐在電腦前,Claude 卡住你會看到;排程跑的時候,你在睡覺。
這是第五幕「讓方法持續運作」的第一篇。前 27 天的方法,都是我坐在電腦前一次一次跑的:每次自己下提示,交出去的是一次指令,我是使用者,這是第一階。今天爬到第二階:交給排程,交出去的是一份契約,我變成設計契約的人。
昨天結尾留了一個問題:重送的規則寫好了,但每一次都是我手動啟動、跑完再看紀錄。如果改成定時自己跑,連被叫醒的人都沒有,它還能把工作接下去嗎?今天回答這個問題,順便把 Claude Code 的排程從頭講一次。
官方提供三種,再加上很多人自己接的第四種:
/loop |
Desktop 排程 | 雲端 Routines | claude -p+系統排程 |
|
|---|---|---|---|---|
| 在哪裡跑 | 目前這個對話 | 你的電腦 | Anthropic 雲端 | 你的電腦 |
| 要開著什麼 | 電腦與這個對話 | 電腦醒著、App 開著 | 都不用 | 電腦 |
| 讀得到本機檔案 | 可以 | 可以 | 不行,每次重新 clone repo | 可以 |
| 每次記得上一次嗎 | 記得,同一個對話 | 不記得,每次新的工作階段 | 不記得 | 不記得(除非 --resume) |
| 錯過時間 | 不補,閒下來時跑一次 | 補跑一次(7 天內最近那次) | 文件未寫 | 看系統排程的設定 |
| 上一輪還沒跑完 | 排隊,等這輪結束 | 跳過,歷史紀錄寫原因 | 文件未寫 | 文件未寫,要自己處理 |
我很早就想讓 Claude 半夜跑雜務,還在簡報裡替它取名「夜鷹計畫」,旁邊自己註記:可靠性待補。真正跑起來的是今年 6 到 8 月:桌面 App 裡三個任務跑了 61 次,大多數早上,我打開電腦時報告已經在那裡;開頭那支每日體檢,則是 Windows 工作排程器裡的一支 claude -p。
怎麼選,看你要它做什麼:
/loop:盯著一件正在進行的事。 部署跑完沒、CI 過了沒、PR 有沒有新留言,有結果就停。claude -p+系統排程:要放進既有流程,或要自己控制每個參數。 我每天早上的專案體檢就是這種;Day 19 的固定檢查,也可以放進 CI 每晚跑。設一個 Desktop 排程只要四欄:名稱、描述、指示、排程,指示下方選權限模式、模型與工作資料夾。官方建議建好後先按一次 Run now,把會用到的工具都選「always allow」;不然排程會停在那裡等你核准,而你正在睡覺。這一步我實測時就卡住了,後面會講。
設起來很簡單,難的是設好之後。
Day 20 我做過一件事:拿掉自己的設定,看同事拿到 Skill 還能不能跑。結果發現很多步驟,其實是我一直在旁邊補。
排程是更嚴格的「別人」:它沒有對話歷史、不能問你問題、半夜才跑,跑錯了也沒有人在場。我那份週報任務的提示,第一段就是這樣寫的:「這是排程自動執行、沒有對話歷史,請完全自包含完成,且不要互動式提問(沒有 user 可回答)。」
所以交給排程,最大的改變不在 Claude,而在你:你寫的不再是提示,而是一份契約。 提示寫錯,你當場看得到、當場改;契約寫錯,它會在你睡著的時候照著錯的跑。
好消息是,這份契約的每一條,前四幕都已經做過一次:
| 契約要回答的 | 前面哪一天做過 | 交給排程時變成 |
|---|---|---|
| 有沒有變好? | Day 5 先把尺放好 | 每輪留紀錄,事後才算得出來 |
| 怎樣才算做完? | Day 6 先約好完成條件 | 不看退出碼,看外部核對 |
| 哪些核對不必每次重想? | Day 19 固定核對交給程式 | 資料由程式產出,Claude 只負責判斷 |
| 沒有我,還能跑嗎? | Day 20 拿掉作者的設定 | 提示自包含、權限事先放行 |
| 改了會不會改壞? | Day 21 Skill 回歸 | 考卷每晚自己跑一次 |
| 結果交給誰? | Day 22 把分工寫成規則 | 失敗、缺資料時交回哪個人 |
| 真的送到了嗎? | Day 23 到接收端逐筆核對 | 做過什麼,記在 Claude 外面 |
| 有副作用的動作誰擋? | Day 27 固定入口 | 煞車裝在 Claude 外面 |
前 27 天學的不是 27 個技巧,而是一份可以交給排程的契約。
Day 23 抓到一個監控看不見的問題:發送端記著送出 9 筆,接收端只收到 3 筆,是演練跑完、我手動逐筆比對才發現的。這種檢查不該等人想起來才做,所以今天把它排成每天凌晨跑一次。
但半夜找到沒送到的通知之後,要怎麼辦?直接補送嗎?Day 27 說過,重送前要先答得出「我確定它沒做嗎?」,凍結期間還不能送;半夜沒有人能回答這些。所以這個排程只負責「發現」,補送留給人。
交給人的方式,就是值班平常的做法:開一張單。早上值班的人打開看板,看到單就去查、去決定要不要補送。整個任務是這三步:
開單看起來最安全,卻有一個 Day 27 開頭提過的風險:我自己維護的維運看板,安全檢查裡就列著「建單若沒有冪等鍵,重送就會重複建單」。這也不是假設:團隊的維運單系統在 6 到 9 月,有 131 張值班任務單,其中 123 張和已經存在的漏洞單標題一模一樣,是另一個系統自動多開出來的,跟 Claude 無關。同一個問題,變成了兩張單。所以這個任務成不成功,就看單有沒有開對、有沒有只開一次。
為了能重複實驗、故意製造故障,我用 claude -p 加一支模擬排程器 run.py 來觸發,每次觸發都是全新的工作階段。同一個任務,我也放進真的 Desktop 排程,每分鐘觸發一次,跑了 13 輪。Claude 只拿到兩支工具:check_notifications.py 只能讀;open_item.py 開待處理單,而且故意等 20 秒才回應,模擬下游慢。驗收一律看服務端留下的紀錄,不看 Claude 怎麼說。
八組跑下來,有三個意外。
今天的資料裡有 2 則通知沒送到,正確答案是 2 張單。凌晨任務最常遇到的狀況是:上一輪還在等下游回應,下一輪的時間到了。我讓第一輪開始 30 秒後就觸發第二輪。

依原始紀錄整理的手繪示意,時間位置不作精密量測;原始數據圖保留完整時間軸。
看 A1 的兩條橫條:第二輪開出 W-003 時,第一輪還沒結束。資料讀自服務端紀錄,各組只跑一次。
| 做法 | 第二輪的 Claude 怎麼說 |
|---|---|
| 不加鎖、每次都開新的 | 「兩張都是新建立的,沒有重複開單」 |
| 不加鎖、開單系統以「訂單+異常類型」去重 | 看到回應寫著已存在,沒有重試,請值班人員確認是否重複 |
| 外層加鎖,上一輪沒結束就跳過 | 沒有派送,排程器記下 skipped: previous_run_active |
它不是在說謊。新的工作階段本來就沒有前情,「我沒有重複」在它自己的工作階段裡是真的,放到整個系統就是假的。Day 27 提過的中斷實驗也是同一件事:寄到第三封時強制結束,換新的工作階段重跑,它把前三封又寄了一次,還回報「每張只寄一次」。
Desktop 排程碰到上一輪沒跑完,確實會自己跳過:11 分鐘裡觸發約 11 次,只啟動 5 輪,每一輪都等上一輪結束才開始。可是 2 個沒送到的通知,前後一共開了 12 張單:每一輪正常跑完,就開 2 張。(沒開單的兩輪,一輪是我把服務開在被佔用的埠,一輪讀到了實驗留在工作目錄的資料檔。)不重疊,不等於不重複:每一輪都是新的工作階段,都覺得自己是第一次開。claude -p 搭系統排程連跳過都沒有,要自己加鎖。我也在資料裡放了一筆同訂單、同異常的重複列,這次 Claude 自己認出來,只開了一張,但能不能認出來,不該是唯一的防線。
鎖擋重疊,去重擋重複,兩個都要,而且都放在 Claude 外面。

鎖管同時執行,去重管已做過的事;兩者不能互相替代。
我故意做了兩種失敗,各跑兩次:
這四次,退出碼全部是 0,結果欄位寫的也是 success。
Claude 自己倒是很誠實:「什麼都沒檢查到……這不代表沒有異常」「今天的通知對帳沒有完成」。可是這些話只在回覆文字裡。排程器如果只看退出碼,四次都會記成成功。權限被拒的那兩次,結果裡另有一個 permission_denials 欄位可以抓;資料源壞掉的那兩次,只能靠外面去核對。
Desktop 排程也一樣。那 13 輪的執行紀錄,全部標成「成功」:包括拿錯資料、回報「未檢查」的那一輪,被我中途停掉的那一輪,還有被煞車擋下、一步都沒做的四輪。

*依原始紀錄整理的手繪示意,時間位置不作精密量測;原始數據圖
上排是執行紀錄,下排是服務端實際收到的。兩段灰底是一輪卡住時,後面每分鐘的觸發都沒有啟動。
更麻煩的是權限。我第一次按 Run now,Claude 下了一條組合指令(Set-Location ...; Get-ChildItem; python check_notifications.py),停下來等核准。我這次遇到的對話框只有三個選項:拒絕、允許一次、允許並切換到「自動」模式(只限這一輪),沒有官方文件說的 always allow。

排程跑到第一個指令就停在這裡。三個選項都只對這一輪有效。
按了允許一次,下一個工具又停;下一輪換個寫法,又停。而且卡住的那一輪沒結束,後面每分鐘的排程一輪都不會啟動,執行紀錄裡也看不到這些被擋掉的觸發。最後是把任務本身的權限模式改成「自動」,才不必人在旁邊。
開頭那三週是 exit=1 沒人看;這裡是「成功」卻什麼都沒做。後一種我在真實工作裡也遇過不只一次:8 月用 claude -p 寫的派工執行器,退出碼 0、費用照扣,產出是零個 commit,之後我加了「零 commit 一律判失敗」;排程報告天天寫「1/12,與昨日相同」,實際早就是 2/12,因為它讀的分支停在三天前。另一個團隊的做法很值得抄:結果分成正常、有問題、檢查器自己壞了三種,今天沒檢查,不等於今天沒問題;看板上也顯示近 24 小時實際觸發了幾次,防止「燈是綠的,其實根本沒跑」。
資料源一直壞掉那組,Claude 每一輪都照實回報沒做完。可是下一次觸發,它還是會被叫起來、再試一次、再花一次錢。沒人在旁邊,煞車就得裝在外面。
我在外層排程器加了一條:連續兩輪沒從服務端取到資料,就寫下 STOP;第三次觸發看到 STOP,不派送,改留一份交回人的紀錄。
Desktop 排程沒有「派送前」可以插腳本的地方,所以我改用 hook:在任務的工作資料夾設一個 UserPromptSubmit hook,看到 STOP 檔就擋下。放下 STOP 之後的四輪,都在 Claude 動手前被擋住,服務端零請求。要注意兩件事:hook 要裝在任務實際的工作資料夾,不一定是提示裡寫的那個;被擋下的四輪,紀錄一樣是「成功」。
有副作用的動作,另外在執行前由程式擋。Day 27 的重送入口就是這種:入口照政策擋下,不靠 Claude 自己判斷該不該送。
成本也是煞車條件。開頭那三個桌面排程跑的 61 次裡,有 10 次失敗,其中 8 次是「已達每週用量上限」,有一週的團隊週報就因此整份沒產出。模型也要寫死:CLI 的預設模型曾被切成最貴的那一個,沒寫死模型的每日體檢就跟著用最貴的跑;這次 Desktop 實驗建任務時沒選模型,跑的也是最貴的那個。
三個意外,加上錯過時間要不要補,就是這份契約要寫的東西。契約不是 Claude Code 的某個設定,要拆到提示、排程設定和 Claude 外面的程式。兩種本機排程拆法不一樣,下表除了註明「本次未驗」的格子,都在兩組實驗裡跑過。標 ★ 的是 Claude 排程特有的,其他是任何 cron 都該有的常識:
| 項目 | claude -p+包裝腳本 |
Desktop 排程 |
|---|---|---|
| ★ 沒有人也能跑 | 提示寫明「排程執行、沒有對話歷史、不要提問」;--allowedTools 列出工具 |
同一段提示;任務權限模式設成「自動」,逐次按允許沒用 |
| ★ 模型與上限 | --model sonnet --max-budget-usd 1 |
建任務時選模型;沒選就用預設 |
| ★ 做過什麼 | 記在開單系統與服務端,不靠 Claude 記得 | 同左 |
| 防重疊 | 包裝腳本加鎖,上一輪沒結束就記 skipped |
內建,上一輪沒結束就不啟動 |
| 防重複 | 開單系統以「訂單+異常類型」去重 | 同左;不重疊擋不住重複 |
| ★ 判斷成功 | 讀結果的 permission_denials,再對服務端紀錄;不看退出碼 |
執行紀錄全是成功,只能對服務端紀錄 |
| ★ 停止條件 | 連續兩輪失敗寫 STOP,包裝腳本不派送 |
工作資料夾的 UserPromptSubmit hook 看到 STOP 就擋下 |
| 其他常識 | 缺資料寫「未檢查」;錯過時間在系統排程勾「盡快補跑」;交回人寫明原因、影響範圍、恢復步驟 | 同左;錯過時間內建補跑一次(官方文件,本次未驗) |
表裡「錯過時間」那一項,我是吃過虧才寫進去的。我自己在跑的一個長期實驗,排程時鐘和執行引擎在 10-06 凌晨無聲無息地停了:沒有錯誤紀錄,電腦也沒重開機。隔天凌晨我發現後手動重啟,引擎照設定只補跑最近一次;另一條排程因為執行器正在忙,直接被跳過。同一天早上,它們又消失了一次,原因到現在還沒查明。
交回人之前,要先決定哪些動作得停下來叫人。讓 AI 自動做事,業界常用三種分法描述人站在哪裡:
排程跑的時候本來就沒有人,所以不是整個排程選一種,而是替每個動作選:讀資料、比對,做錯重跑就好,人不參與;開單、重送,人退到 on,規則先寫好,重送走 Day 27 的固定入口;查不到、連續失敗、凍結中,繼續做就是在猜,人回到 in:停下來,叫人。
只讀、重跑也無妨的任務,Desktop 排程最省事;要外層煞車、要精確控制參數的,用 claude -p 加包裝腳本。第一個排進去的,挑每天都要做、只讀的工作。
想自己跑一次,到教學包目錄執行(需要 Python 與 Claude Code CLI,三組約 US$0.1):
python run.py A1 A3 D
# A1/items.json 應該有 4 張;A3/scheduler.jsonl 會有 skipped,D/scheduler.jsonl 會有 not_dispatched
靠得住,但靠的不是 Claude 的記憶,而是你放在它外面的東西:記得做過什麼的狀態、擋住重疊的鎖、判斷成敗的核對、會自己踩的煞車。Claude 在這裡其實很穩:它照實說沒做完、看到可疑的回應就交回人、認得出重複的資料。它做不到的,是知道上一個自己做過什麼。
所以第二階的人,不在凌晨的按鈕旁邊,而在契約、紀錄和煞車那一側。你從下指令的人,變成了設計系統的人。
但第二階有它的天花板。排程只會查你事先想到要查的東西:今晚的通知檢查再穩,也不會發現你沒寫進檢查的那種問題。
另一個天花板是你自己。通知檢查排好了,晨報也排了,回歸、Wiki、Skill 考卷一個個跑起來;每天早上,等我處理的單、交回人的紀錄、要確認的重複,全部湧進來。排程都跑起來了,為什麼我反而更忙? 明天 Day 29 談這件事。
參考資料:
/loop、三種排程比較表)、Desktop scheduled tasks(補跑、跳過、權限)、Routines、Headless mode、CLI reference(2026-10-11 查閱;Routines 為 research preview)。criteria.md、本機服務 service.py、兩支工具範本、排程模擬 run.py,以及八組實跑的工具軌跡、服務端請求紀錄、開單紀錄、排程器紀錄與交回人紀錄。days/day28/lab-interrupt:Day 27 提到的中斷重跑對照,六組的判準、腳本與接收端紀錄。days/day28/lab-desktop:Desktop 排程實驗的判準、任務提示、hook 腳本與逐輪紀錄。claude -p 加模擬排程器,不是 Desktop 排程或 Routines 本身;鎖、停止派送都是外層腳本的邏輯,不是 Claude Code 內建;去重只證明這條約定在本機成立。