Claude Codeを寝ている間に回す――自宅サーバのcronから、Mac miniのlaunchdに落ち着くまで
目次
朝、起きてSlackを開くと、昨夜の自分ではない「誰か」が仕事を済ませてある。保守依頼がチケットになっていて、ブログ記事のPRが1本立っていて、重要なメールだけが要約されて届いている。全部、私が寝ている間にClaude Codeが勝手にやったものだ。
きっかけは、1チケットを自律で消し切るループを作ったときに感じた物足りなさだった。せっかく1枚を安全に消せるループができても、それを「起動する」のが手作業のままなら、結局は私が机の前にいる時間しか動かない。だったら時計に任せればいい。決まった時刻に、無人で、勝手に立ち上がってほしい。
本記事では、Claude Codeをインタラクティブな道具としてではなく、無人の定期ジョブとして自宅で回している、その実装を共有します。認証をどう省いたか、暴走をどう止めているか、そしてcronで嵌まってlaunchdに引っ越した正直な経緯まで。派手なAIの話ではなく、どちらかというと地味な段取りと安全弁の話です。
何を寝ている間に回しているか
いま自宅で自動発火しているジョブは10本ほどある。中身は雑多だが、性格でおおまかに3つに分かれる。
まず受託業務の下ごしらえ。ある顧客の依頼が流れてくるSlackチャンネルを毎日決まった時刻に見に行き、新しい依頼をNotionの保守チケットとして起票し、関連する機能に紐づけて概算見積まで付ける。転記が終わったら返信はせず、📝のリアクションだけ残す――「読んで処理したよ」の印だ。続けて、そのチケットが人間の判断を要するかどうかだけを仕分ける。ここまでが1本のジョブに繋がっている。
次に自分の発信まわり。日曜の朝に、アクセス解析を実測して今週書くべき記事の案を7本ぶん出す。そして毎朝、そのキューから未消化の1本を選んで記事を書き、feat/blog-* ブランチでPRを立てる。まさにこの記事も、その日次ジョブが動かしているスキルの産物だ。
最後に見張り役。未読メールから本当に対応が要るものだけを抜き出して通知する。全ジョブのログを日次で要約する。そして、前夜のジョブのうち最新の実行が失敗しているものだけを拾って、原因と直し方の案をDMで投げてくる。無人で動くものが増えるほど「今どれが動いていて、どれが転んだか」を見える化する仕組みが要る、というのはエージェントの監視ダッシュボードを作った話でも痛感したところだ。
共通しているのは、どれも「毎回同じ段取りを、決まった時刻に踏むだけ」の仕事だということです。頭を使う部分ではなく、手が塞がる部分。ここを時計に預けると、机に向かえる時間の外側でも仕事が進みます。
ジョブの中身そのものは、リポジトリ直下の SKILL.md に書いてある。挙動を変えたいときは時計の設定ではなくスキルを直す。時計(launchd)は薄い引き金で、何をするかはスキルが持つ、という分担にしている。
認証は「自前botを立てない」で済ませた
無人でSlackやNotionを触ると聞くと、まず「botトークンやAPIキーの管理が面倒そう」と思う方が多い。私もそう思っていた。でも、ここは拍子抜けするほど軽く済んだ。
からくりは、headlessの claude -p(プロンプトを渡して非対話で走らせるモード)が、普段自分がClaude Codeで使っているのと同じ claude.ai のSlack/Notionコネクタをそのまま借りられることにある。つまり無人ジョブ専用のbotもトークンも発行していない。OAuthで繋いだコネクタを、無人プロセスがそのまま使う。
正直に言うと、これは楽をした部分だ。専用の権限体系を組むより、既にある接続に相乗りするほうが手が少ない。副作用として、コネクタが切れると全ジョブが黙って何もできなくなるので、claude mcp list で接続が ✔ になっているかを時々確認する運用にしている。ここは自動化しきれていない、人間の目視が残っている箇所だ。
いちばん時間をかけたのは「安全弁」
無人ループでいちばん怖いのは、賢く動くことではなく、間違ったまま静かに突き進むことだ。だから設計の重心は、速さでも賢さでもなく、触らせない範囲を先に決めることに置いた。
具体的には、各リポジトリ直下の .claude/settings.local.json に、そのジョブが使っていいツールだけを列挙する(scoped allowlist)。ここに書いていないツールは、そもそも呼べない。
線の引き方はジョブの性格で変える。
- 顧客のチケットを起票する見張り系のジョブには、Slack/Notionと
rg・lsくらいしか渡していない。WriteもgitもないのでコードやDBには一切手が出せない。読んで、判定して、Notionを更新するだけ。 - ブログの記事を書く日次ジョブには、Write・git・
gh pr createを許す。記事を書いてPRを立てるところまでは無人でやってほしいからだ。
そのうえで、ブログ系にはもう1本だけ、明確なdenyを足している。gh pr merge は禁止だ。
記事の執筆とPR作成までは無人でやらせても、マージ=公開の判断だけは人間に残す。AIが書いたものが、私のレビューを一度も通らずに世に出ることは構造上起きないようにしています。allowlistで「できること」を絞り、denyで「してはいけない一線」を重ねる。この二重化が、無人で回すときの精神的な安心料でした。
コード改変が絡むジョブも同じ思想で、PRを立てるところで止める。マージも、本番へのデプロイも、最後は人間が押す。無人化したのは段取りであって、意思決定ではない――この線を引けたことが、安心して寝られる理由になっている。
cronで始めて、launchdに引っ越した
ここからは、うまくいかなかった話をする。
最初はごく素直に、cron に載せた。UNIXの定番だし、0 8 * * * と書けば毎朝8時に動く。頭では、それで終わりのはずだった。
ところが、朝になってもジョブが動いていない日がぽつぽつ出る。ログを見ると、そもそも起動した形跡がない。原因は間抜けなもので、発火時刻にマシンがスリープしていた。macOSのユーザーcronは、スリープ中に来た発火時刻を後から取り返してくれない。飛ばしたら、飛ばしっぱなしなのだ。24時間つけっぱなしのサーバなら気にしなくていい話が、家庭の環境ではそのまま穴になった。
そこで launchd の StartCalendarInterval に移した。これは、発火時刻にスリープしていても、次に起きたときに取りこぼしを実行してくれる。「8時ちょうど」ではなくなるが、「起きたら必ず実行される」ほうが、家で回すには合っていた。間に合わなかった、では困る。遅れてでも動くことのほうが大事だった。
引っ越しはもう一段あった。当初は常時稼働の自宅サーバ(Linux機)で回していたのだが、これが発熱の面で不安を抱える個体で、無人で放置し続けるのはやめる判断をした。いまはMac miniにジョブを寄せている。無人自動化は「動かし始める」より「安心して放っておける置き場所を決める」ほうが、実は難しかった。
静かに動かなかった夜の話
もう一つ、しばらく気づけなかった失敗を書いておきたい。
ブログ関連の週次・日次ジョブが、ある時期まったく動いていなかった。エラーも吐かない。ログにも派手な赤字は出ない。ただ、成果物だけが生まれない。いちばん質の悪い壊れ方だった。
原因は2つ重なっていた。1つは、ジョブを起動する薄いラッパースクリプトの中で、claude -p に渡す引数の順序を間違えていたこと。可変長で受ける --allowedTools の指定が、本来渡すべきプロンプト文字列を飲み込んでしまい、Claudeは「空の指示」を受け取って何もせず正常終了していた。もう1つは、そのジョブが使うスキルを呼ぶための Skill ツールを、allowlistに入れ忘れていたこと。安全弁を厳しくした反動で、肝心の仕事道具まで締め出していたわけだ。
エラーで止まってくれるならまだいい。この手の無人ジョブがいちばん怖いのは、**「正常終了しているのに、何もしていない」**という顔をされることだ。だから今は、失敗を拾う見張りジョブとは別に、「成果物が生まれているか」を人間が時々のぞく癖をつけている。緑のログは、必ずしも仕事をした証拠ではない。
うちも無人でエージェントを回してみたい、という方へ。派手な失敗より、この「静かに何もしない」を疑えるかどうかが、無人化の分かれ目だと思う。
まとめ
Claude Codeを寝ている間に回す、と言うと最先端の響きがあるかもしれない。でも、実際にやっていることの中身は、驚くほど古典的だ。同じ段取りを時計に預け、触らせない範囲を先に決め、最後の一線は人間が押す。新しいのは道具だけで、考え方はずっと昔からある運用の作法そのものだった。
無人化で得たいのは「AIがすごい」ことではなく、頭を使うべき場所に頭を戻せることだ。段取りを時計に渡したぶん、私は「何を直すか」「何を書くか」を考える時間に戻れる。そのために要ったのは、賢いプロンプトよりも、地味な安全弁と、失敗を疑い続ける目のほうだった。
無人で回した続き――どのジョブがどう転んで、どう直したか――は、もう少し運用の傷が増えたら、また書きたいと思います。
1チケットを自律で消し切るループを作った
今回の定期ジョブが「起動している」中身の1つ。司令塔1・マネージャ1・専任3の3層で、1チケットを検証つきで安全に閉じるループの設計です。
/blog/claude-code-autonomous-ticket-loop/
関連記事
- 技術
1チケットを自律で消し切るループを作った――司令塔1・マネージャ1・専任3の敵対的レビュー付き設計
Claude Codeで課題トラッカーのチケットを「完了相当」まで自律処理するコマンドを設計・実装した記録です。司令塔1・マネージャ1・専任3体の3層構成、TC作成から実装・レビュー・PRまでのパイプライン、逐次と確認の扱い、そして多エージェントの敵対的レビューで設計を詰めた過程を、正直な未検証点も含めて共有します。
ClaudeAIマルチエージェント - 技術
Claude Codeマルチエージェントのリアルタイム監視ダッシュボードを作った
Claude Codeをtmuxで11人編成のマルチエージェントとして運用する中で生まれた「誰が何をしているか分からない」課題を、173行のBashスクリプトによるターミナルTUIダッシュボードで解決した設計と実装の記録。
ClaudeAIマルチエージェント - 技術
Claude Codeで11人編成のマルチエージェント開発チームを構築した話
Claude Codeで11人編成のマルチエージェント開発チームをtmuxベースで構築した記録。役割分離、通信プロトコル、Gate Systemによるフェーズ制御、監視ダッシュボード、コストまで実運用の知見を共有する。
ClaudeAIマルチエージェント
