Mac miniでClaude Codeを24時間回したいのに、朝起きたら止まっていた。これ、めっちゃあるあるですよね。この記事は、Mac mini Claude Code運用を本気で安定させたい人、tmux 自動再起動まで作っても再起動やネット断で落ちて悩んでいる人に向けて書きました。読むと、tmux・launchd・Healthchecks・Slack/ntfyをつないだ「止めない設計」をそのまま再現できます。僕は福祉事業のIT全般を担当しつつ、日々ターミナル中心でAIエージェントを回しているので、実運用で詰まりやすいポイントを具体的に共有します。
こんな方におすすめ
- Mac miniでClaude Codeを常時動かしたいのに、夜間停止が頻発している方
- tmuxは使っているけど、異常終了時の復旧が手動のままな方
- 再起動・スリープ・ネット断まで含めてAIエージェント 24時間 運用を作りたい方
- 通知が遅れて、気づいた時には数時間ロスしてしまう方
この記事でわかること
remain-on-exitとrespawn-paneでtmux復旧を自動化する方法- launchdの
KeepAliveとStartIntervalを使った再起動後の復帰 - Healthchecksで「マシンごと落ちた」を検知する死活監視の実装
- Slack/ntfyで誤報を減らしつつ見逃しも減らす通知設計
なぜMac mini運用でもClaude Codeは止まるのか(障害レイヤーを分解)
先に結論です。止まる理由は1つではなく、障害レイヤーが分かれているからです。Mac mini M4 Pro自体はかなり安定しています。Apple公開値でも、2024年モデルはアイドル5W、最大140Wクラス、さらに静音性は約5dBAです。つまり、ハード側のポテンシャルは高いです(Appleの環境仕様 / Mac mini技術仕様)。それでも止まるのは、復旧ポイントが1段だけだと、別レイヤーの障害を拾えないからです。
- プロセス障害 — Claude Codeが例外終了、APIエラーで停止
- セッション障害 — tmuxのpane終了、window構成の崩れ
- ホスト障害 — macOS再起動、スリープ、ネット断、電源断
イメージとしては、家の中で扇風機だけ直してもブレーカーが落ちたら全部止まるのと同じです。なので「tmuxだけで完結」だと穴が残ります。僕が実際に安定したのは、tmuxで局所復旧、launchdでOS復旧、Healthchecksで外形監視、通知で即応という4層に分けてからです。
| 障害レイヤー | よくある停止 | 復旧担当 | 検知手段 |
|---|---|---|---|
| プロセス | Claude Code異常終了 | tmux hook | pane-died / pane-exited |
| セッション | pane停止・window崩壊 | tmux respawn | tmux内チェック |
| ホスト | 再起動・電源断・ネット断 | launchd + Healthchecks | 外部ハートビート欠損 |
tmux自動再起動の実装(remain-on-exit・respawn-pane・hook)
ここは最初の土台です。「落ちた場所だけ戻す」設計にすると、復旧が速くなります。公式仕様どおり、remain-on-exit failedで失敗paneを残し、respawn-pane -kで同ターゲットを再起動します。さらにpane-diedフックで自動復旧スクリプトを呼ぶと、寝ている間の停止もかなり減ります。
# ~/.tmux.conf
set -g remain-on-exit failed
set -g status-interval 5
set-hook -g pane-died "run-shell '~/ops/claude/recover-pane.sh #{session_name}:#{window_index}.#{pane_index}'"
set-hook -g pane-exited "run-shell '~/ops/claude/notify-pane-exit.sh #{session_name}:#{window_index}.#{pane_index}'"
#!/bin/zsh
# ~/ops/claude/recover-pane.sh
set -euo pipefail
TARGET="$1"
/usr/local/bin/tmux respawn-pane -k -t "$TARGET"
/usr/bin/curl -fsS -X POST \
-H 'Content-type: application/json' \
--data "{\"text\":\"[tmux] pane復旧: ${TARGET}\"}" \
"$SLACK_WEBHOOK_URL" >/dev/null
注意点は、無限再起動ループを作らないことです。例えば同じpaneが連続3回落ちたら手動確認に切り替える、という分岐を入れると安定します。参考として、autoclaudeは3秒ポーリングで「解除後continue」を自動化していますが、僕はまずtmux hookで落ちた瞬間に動く構成を先に作るのがおすすめです(autoclaude)。
- 復旧対象を限定 — セッション全体ではなく落ちたpaneだけ再起動
- 通知を同時実行 — 復旧成功でもログを残す
- 連続失敗に上限 — 3回などで自動復旧を止めて原因調査
launchdで再起動後も自動復帰させる(LaunchAgent完全設定)
tmux復旧だけだと、Mac再起動後に空っぽのままになることがあります。ここを埋めるのがlaunchdです。KeepAliveで常駐、StartIntervalで定期起動を重ねると、復帰の抜けがかなり減ります。僕はLaunchAgentでtmuxサーバー起動スクリプトを常駐化しています。
# ~/Library/LaunchAgents/com.masu.claude-daemon.plist の要点
Label: com.masu.claude-daemon
ProgramArguments: ["/bin/zsh", "/Users/you/ops/claude/start-claude.sh"]
WorkingDirectory: /Users/you/workspace
KeepAlive: true
StartInterval: 300
StandardOutPath: /Users/you/Library/Logs/claude-daemon.log
StandardErrorPath: /Users/you/Library/Logs/claude-daemon.err.log
# 反映と再起動
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.masu.claude-daemon.plist
launchctl kickstart -k gui/$(id -u)/com.masu.claude-daemon
ここでハマりやすいのがStartIntervalへの過信です。仕様上、スリープ中やジョブ実行中の発火取りこぼしがあります。さらにlaunchdには短周期再spawnの抑制(既定10秒)もあります。なので、launchd単体ではなく、tmux側の復旧とセットで使うのが安定します。
- 起動保証 — launchdで「OS起動後に必ずstartスクリプト実行」
- 局所復旧 — tmux hookで落ちたpaneだけ即復旧
- 外部監視 — 後段のHealthchecksでホスト障害を補足
死活監視の実装(Healthchecksで“マシンごと落ちた”を検知)
tmux監視だけでは、Macごと落ちた時に検知できません。ここはHealthchecksのハートビートが強いです。「成功pingが来ない」を監視するだけで、電源断・ネット断・cron停止まで拾えます。僕はwatchdogスクリプトの最後にpingを打つ運用にしています。
#!/bin/zsh
# ~/ops/claude/watchdog.sh
set -euo pipefail
HC_URL="https://hc-ping.com/your-uuid"
# 監視開始通知
curl -fsS -m 10 --retry 5 -o /dev/null "${HC_URL}/start"
# tmuxセッション確認
/usr/local/bin/tmux has-session -t claude-main
# ここまで成功したら成功ping
curl -fsS -m 10 --retry 5 -o /dev/null "${HC_URL}"
Healthchecks初期値で押さえるポイント
- Period — 自動プロビジョニング既定は1日です
- Grace — 既定1時間なので、短運用なら短く詰めると見逃しが減ります
- チェック上限 — Free 20件、Paidは100または1000件です
僕のおすすめは、5分実行なら「Period 5分 / Grace 7〜10分」くらいから始める形です。誤報が多い場合はGraceを少し広げます。逆に夜間停止が痛い場合は、通知優先で短くします。つまり、監視は入れるだけで終わりではなく、運用に合わせて調整していくのがコツです。
通知設計の実装(Slack/ntfy多重通知と誤報抑制)
監視を入れても、通知が埋もれたら意味がありません。なので僕はSlackとntfyの2系統にしています。通知は「届く確率」を上げる設計が最優先です。Slackは履歴管理、ntfyはスマホ即時受信が強みです。
#!/bin/zsh
# ~/ops/claude/notify.sh
set -euo pipefail
MSG="$1"
curl -fsS -X POST \
-H "Content-type: application/json" \
--data "{\"text\":\"${MSG}\"}" \
"$SLACK_WEBHOOK_URL" >/dev/null
curl -fsS \
-H "Title: Claude Watchdog" \
-d "${MSG}" \
"https://ntfy.sh/your-topic" >/dev/null
誤報を減らすには、同一アラートのクールダウンを入れるのが有効です。例えば「同じエラー文言は10分以内なら再送しない」にすると、深夜の通知爆発を抑えられます。GUI中心で管理したいならClawTabのような選択肢もありますが、僕はまずシェルで仕組みを固めてからUIを乗せる流れがやりやすかったです(ClawTab)。
| アプローチ | 強み | 弱み | 向いている人 |
|---|---|---|---|
| autoclaude | レート制限後のcontinue自動化が速い | ホスト障害の検知は別途必要 | 既存tmux運用を素早く改善したい人 |
| ClawTab | cron/tmux/通知をGUIで一体管理しやすい | 設計意図がブラックボックス化しやすい | UI中心で運用したい人 |
| 本記事の4層構成 | OS復旧・外形監視・通知まで分離できる | 初期実装は少し手間がかかる | 24時間運用を長期で回したい人 |
このあたりの設計を自分環境に合わせて詰めたい人は、フリーランスエンジニアのキャリア相談(PR)でも壁打ちできます。運用フローを一緒に分解すると、復旧時間はかなり短くなります。
運用Runbook(障害時の確認手順・再発防止・定期メンテ)
仕組みを作ったら、最後はRunbookです。ここがあると、深夜障害でも迷わず復旧できます。「誰が見ても同じ手順で戻せる」状態を作るのがゴールです。
- 通知確認 — Slack/ntfyの時刻とエラー種別を確認します
- tmux状態確認 —
tmux ls/tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} #{pane_dead}' - 手動復旧 — 必要なら
tmux respawn-pane -k -t セッション:ウィンドウ.ペイン - launchd再読込 —
launchctl bootout後にbootstrap、最後にkickstart -k - 再発防止メモ — 失敗時刻、原因候補、対策を1行で残します
週1でやっている定期メンテも共有します。ログ肥大化確認、Webhookの有効期限確認、HealthchecksのGrace見直し、そして通知テスト送信です。これだけで「気づかなかった停止」はかなり減ります。関連記事として、Mac miniでAIエージェント環境を作る手順とGhostty + tmuxの作業環境構築も合わせて読むと、再現しやすいです。
「実装時間を短くしたい」「自分の案件構成に合わせて最適化したい」という場合は、運用設計の相談(PR)を使ってくれたら助かるな、という感じです。
この設計を入れないまま1年運用すると起きること
tmuxだけで回し続けると、止まった時に気づくのが遅れます。すると、小さな停止が積み上がって、月単位でかなりの時間損失になります。知らないままだと、次のような状態になりやすいです。
- 復旧の属人化 — 自分しか戻し方を把握していない
- 機会損失 — 夜間バッチや定期処理が止まって朝に再実行
- 精神コスト増 — 「止まってないかな」を毎日確認する負荷
怖がる必要はないですが、早めに4層設計へ寄せると、運用がかなり軽くなります。
この記事を書いている理由
僕自身、Mac mini M4 Pro(24GB)でNode.js + TypeScript + npm workspacesのモノレポを24時間回していて、最初は「tmuxさえあれば十分」と思っていました。でも実際には、再起動やネット断で止まるたびに手戻りが出ました。さらに僕は普段、Ghostty + tmux + Claude Codeをメインにしているので、tmuxが落ちると作業導線が丸ごと止まります。Tailscaleで外から触れる環境も作っているからこそ、通知と復旧がつながる価値を実感しました。同じ遠回りを減らしてほしくて、実装ベースでまとめています。
次のアクション
ここまで読んだら、まずはtmux hookだけでも今日入れてみてください。1時間以内で体感が変わります。実装したら、どこで詰まったかをコメントかSNSで教えてもらえると、次の記事で深掘りします。
今日からできるアクション
- Step1 —
remain-on-exitとrespawn-paneを設定する - Step2 — launchdの
KeepAlive+StartIntervalを入れる - Step3 — HealthchecksとSlack/ntfy通知をつなぐ
- 相談したい方 — フリーランスエンジニアのキャリア相談(PR)へどうぞ