launchd自動コミット × クラウドAIの状態同期問題
「launchd 自動コミット」「git push 競合 解消」「Mac 自動化 git」と検索する人の多くは、ローカルで動かしている自動化処理と、クラウド上のAIエージェントの状態がずれて困っている状況に直面しているはずです。私自身、Mac上のlaunchdで毎日23:00に自動コミットを走らせていた運用に、クラウド側のAIエージェント(GitHub上のリポジトリを参照して動くRoutine)を組み合わせた瞬間、最大23時間のラグが発生する問題にぶつかりました。本記事では、launchd plistの設計、StartCalendarIntervalのarray化、git push競合をrebaseで解消する手順、そして自動化を追求した先にある限界とトレードオフまで、実装ベースで解説します。
ローカルAIとクラウドAIの「状態同期問題」とは何か
まず、なぜlaunchd × クラウドAIエージェントの組み合わせで問題が起きるのかを整理します。
ローカルAI(私の場合はMacのターミナルで動くClaude Code)は、ローカルファイルシステムを直接読み書きします。一方、クラウドAIエージェント(GitHub Actions経由のRoutine、Vercel cron上のスクリプト、リモートエージェントなど)は、ローカルではなくGitHub上のコードベースしか見ることができません。
つまり、ローカルで作業した結果がGitHubにpushされていなければ、クラウドAIは古い状態のまま動きます。これがローカルとリモートの「状態同期問題」です。
具体的にどう困るかというと、私の運用ではこんな現実が起きました。
- 朝、Macで案件のメモやコードを編集する
- 昼、クラウドAIエージェントに「今日の案件状況をまとめて」と指示する
- クラウドAIはGitHub上のコードしか見られないので、昨夜23:00時点のスナップショットで返答する
- 結果、午前中の作業がまるごと反映されていない報告が返ってくる
1日1回の自動コミットだと、最悪のケースで23時間の同期遅延が発生します。これではせっかくのクラウドAIエージェントが、最新状態を見られない「過去視点の参謀」になってしまいます。

同期方式の選択肢を比較する
解決策の方向性は大きく3つあります。
- 頻繁な自動コミット: launchdのスケジュールを増やし、3〜6時間ごとにpushする(私が選んだ方法)
- イベント駆動: ファイル保存をトリガーにした即時push(fswatch + git)
- クラウド側に処理を寄せる: Vercel cronやCloudflare Workersなどクラウド完結のジョブに移行する
結論から言うと、3つすべてに一長一短があります。私はまず一番ローコストな1番目から手をつけました。
launchd 自動コミットの基本構造
「launchd 自動コミット」で検索する方が最も知りたいのは、実際に動くplistとshellの最小構成だと思います。私の現行構成を分解して説明します。
launchdとは何か(最低限の前提)
launchdはmacOSの標準スケジューラです。LinuxのcronやsystemdのTimerに相当します。~/Library/LaunchAgents/にplistファイル(XML)を置いて、launchctl loadで登録するだけで、指定時刻にスクリプトが起動します。
cronと比べた特徴は次のとおりです。
- plistはXML。記述量はやや多いが、構造化されていて読みやすい
- Mac起動中のみ動く。スリープ中は実行されない
- ただし、StartCalendarIntervalで指定した時刻にスリープしていた場合、復帰時に追走実行される(重要)
- 標準出力・標準エラーの出力先をplistで指定できる
plistの最小構成
1日1回、23:00に実行するplistはこのようになります。
~/Library/LaunchAgents/com.example.git-autocommit.plist
- Label: ジョブ識別子(一意になる逆DNS表記)
- ProgramArguments: 起動するコマンドと引数(配列)
- StartCalendarInterval: 起動時刻(dictで指定)
- StandardOutPath / StandardErrorPath: ログ出力先
登録は次の流れです。
launchctl unload ~/Library/LaunchAgents/com.example.git-autocommit.plist(既存があれば)launchctl load ~/Library/LaunchAgents/com.example.git-autocommit.plistlaunchctl list | grep git-autocommitで登録確認
StartCalendarInterval と StartInterval の罠
頻度を上げる方法を調べると、最初に出てくるのがStartInterval(秒数指定)です。一見シンプルですが、私はこれを採用しませんでした。理由は次のとおりです。
- StartIntervalは「launchd起動後N秒経過ごと」に発火する。Macが再起動すると基準時刻がリセットされる
- つまり「毎日0時/3時/6時のような時刻基準」では動かせない
- 運用ログを見て「いつ動いたか」を予測しづらい
そこでStartCalendarIntervalをarray化します。dictを複数並べた配列にすることで、複数の時刻指定が可能になります。
私のケースでは、3時間ごと(0時/3時/6時/9時/12時/15時/18時/21時)の8回スケジュールに変更しました。これなら時刻基準で確実に動き、Macがスリープしていても次の起床時に追走実行されます。

shellスクリプトの最小構成
plistから呼び出すshell側は、次のような構造にしています。
- 対象リポジトリごとにディレクトリを切り替えてgit statusを実行
git status --porcelainで変更検知(出力ゼロ=クリーン)- 変更があればadd → commit → fetch → rebase → push の順で実行
- 各ステップの成否をログに記録(
scripts/logs/git-autocommit.logに追記) - 失敗カウンタを保持し、1件以上失敗したら
osascriptでmacOS通知を出す
シンプルですが、これが「自動化の最小単位」です。最初は1リポジトリ・1スケジュールから始めて、徐々にリポジトリ数とスケジュール数を増やしていくのが安全です。
StartCalendarIntervalのarray化と古いskipロジックの落とし穴
頻度を上げる過程で、私は1つ大きな罠を踏みました。それは「過去に書いた最適化ロジックが、新しいスケジュールと矛盾する」という落とし穴です。
もともとのskipロジック
1日1回・23:00運用の頃、私はこういうロジックをshellに書いていました。
- 「今日23:00以降に成功実行したマーカーファイルがあれば、再実行をskipする」
- 復帰時の追走実行で同じ日に2回commitが走る事故を防ぐためのロジック
この最適化は、1日1回の運用では理にかなっていました。しかし3時間ごとに変更した瞬間、このskipロジックが致命的になります。
- 0時に成功実行 → マーカー更新
- 3時に発火 → 「今日すでに成功しているのでskip」
- 6時、9時…全部skip
- 結果、頻度を上げたつもりが1日1回のまま
ログを見て初めて気づきました。1週間ほど「なぜpushされない時間が偏るのか」と頭をひねった末の結論です。
教訓: 自動化スクリプトのロジックは、スケジュール仕様と密結合している
この経験から学んだのは、自動化スクリプトの中のロジックは、呼び出し側のスケジュール仕様と切り離せない関係にあるということです。スケジュールを変えるなら、スクリプト内の前提も全部見直さないと、見えないバグになります。
具体的にやったのは次の2点です。
- マーカーファイルベースのskipロジックを削除
- 「今走るかどうか」の判断はlaunchd側に完全委譲し、shellは呼ばれたら必ず動く設計に統一
シンプル化の鉄則どおり、判断を1箇所に集める方が長期運用では強いと改めて実感しました。
git push 競合 解消 — rebase戦略の実装
頻度を上げてもう1つ発生したのが、「git push 競合 解消」で検索される現象、いわゆるnon-fast-forward問題です。
競合が発生する仕組み
私の運用ではクラウドAIエージェント(Routine)がGitHubに直接commit・pushします。一方、ローカルのlaunchd autocommitもpushします。タイミングが重なると、こうなります。
- 10:00 ローカルlaunchdがpushして成功
- 11:30 クラウドAIがcommit & push(GitHubが先に進む)
- 12:00 ローカルlaunchdがpushしようとする → 「Updates were rejected because the tip of your current branch is behind」
これがnon-fast-forwardのエラーです。「リモートが先行しているので、追いついてからpushしろ」という警告ですね。
fetch + rebase + push の順番
解消の基本は、push前にリモートの最新を取り込むことです。私はpullではなくrebaseを選びました。
git fetch origin <branch>git rebase origin/<branch>git push origin <branch>
pull --rebaseでも同じ結果になりますが、私はfetchとrebaseを明示的に分けています。理由はログの可読性です。fetchでリモートを取得した時点と、rebaseで取り込んだ時点を別ログ行に出すことで、後でトラブルシュートする際に「どこで失敗したか」が一発で分かります。
rebase失敗時のフォールバック
autocommit運用で最も怖いのは、rebaseが衝突して中途半端な状態のまま放置されることです。コンフリクトしたファイルがworking treeに残ったまま、次のautocommitが走ると、状況が雪だるま式に悪化します。
そのため、私は次の安全策を入れています。
- rebaseの戻り値が0以外なら、即
git rebase --abortで元の状態に戻す - 「rebase failed (conflict), skipped push」とログに記録
- 失敗カウンタをインクリメント
- macOS通知で「⚠ autocommit 失敗」を表示し、私が手動で介入する
rebaseは強力ですが、自動化に任せきれない領域があります。「自動でできる範囲はやる、できない範囲は人間に通知する」の境界線を明確に持っておくことが、長期運用の鍵です。

Mac 自動化 git の限界と現実的な落としどころ
「Mac 自動化 git」というキーワードで来た方に、最後にぜひお伝えしたいのが、launchd × クラウドAIで完全な24/7同期を作るのは不可能だという現実です。
launchdの根本的な制約
launchdは、Macが起動している間しか動きません。次のような状況では確実に同期が止まります。
- 深夜にMacをシャットダウン or 完全スリープ → 朝まで動かない
- 外出中にMacを閉じている → ノートPC前提の運用では4〜8時間止まる
- 長期出張で1週間電源を入れない → 1週間まるごと同期不能
StartCalendarIntervalの追走実行は便利ですが、「現在動いていない時刻が長すぎると、追走しても遅延は埋まらない」のが現実です。
真の24/7が必要な領域はクラウドに移す
では、本当に24時間365日動かしたい処理はどうするか。私の答えは「該当部分はクラウドに移す」です。
- Vercel cron(Hobbyプランで月100実行までは無料)
- Cloudflare Workers Cron Triggers(無料枠が広く、ms単位の課金)
- GitHub Actionsのscheduled workflows(OSS用途なら無料)
ただしクラウドに移すと、ローカルファイルへのアクセスができなくなる、シークレット管理が複雑になる、デバッグがしづらくなる、というコストが発生します。
「自動化のコスト」と「同期遅延のコスト」を天秤にかける
私が最終的に到達した運用方針は、次の2つの分業です。
- ローカルでよい処理はlaunchd: 案件メモ、設計書、開発中のコード。Mac起動中に動けば十分
- 24/7必要な処理はクラウド: 顧客向けの問い合わせ受付、ステータス監視、定時通知
完全自動化を追求するほど、構成が複雑になり、運用負荷が上がります。一方、頻度を諦めれば、launchdだけで多くのケースは十分回ります。
大事なのは「全部を一律に自動化しない」ことです。重要度・即時性・コストを案件ごとに見極めて、launchdとクラウドの境界を引く。これが現場で得たいちばんの教訓です。
関連記事
定期実行の仕組みをさらに比較したい方は、こちらの記事もあわせてどうぞ。
クラウド側のリモートエージェント運用を詳しく知りたい方はこちらです。
まとめ — launchd × クラウドAIは「秘書体験」を作れる
launchd 自動コミットを土台にして、クラウドAIエージェントが常に最新コードを参照できる状態を作ると、「常時稼働するAI秘書」体験は十分に実現できます。私の現在の運用では、3時間ごとの自動push + rebaseフォールバック + 失敗時通知の組み合わせで、業務時間中の同期遅延は最大3時間以内に収まっています。
すべてを自動化しようとするほど、運用は複雑になります。しかし「ここまでは自動、ここから先は人間が判断」という境界をきちんと引けば、launchdは中小規模の自動化において、いまだに最強の選択肢の1つです。Mac 自動化 git の入口として、ぜひ自分の業務に合った組み合わせを探してみてください。
御社の業務に合わせたClaude Code導入支援
「AIツールを導入したが、現場で使われない」を終わらせる。
業務課題のヒアリングから設計、ハンズオン実践、運用定着まで一貫して支援します。