Claude CodeでMacがスリープして止まる原因 — caffeinate中継の隙間と対処
長時間タスクが画面オフの数分後にMacごと止まる。4分ごとに作り直すcaffeinateの隙間が原因とされるissue #81832の機序、pmsetでの確認、外から1本張る回避策、Windowsの現状を書きます。
夜に長いタスクを任せて画面を消したのに、朝になるとMacが眠っていて、セッションが途中で止まっている。caffeinate のプロセスはツリーに見えているのに、です。
GitHubのissue #81832は、この症状の原因を「Claude Codeが caffeinate を作り直す瞬間に、スリープ抑止がゼロになる」ことだと報告しています。issueはopenで、修正バージョンは示されていません。以下では、報告された機序、自分のMacで同じことが起きているかを確かめる方法、いま手元でできる回避策を順に書きます。Windowsでは中継以前に抑止そのものが無いという報告(#96679)も、最後に扱います。
画面を消したあとだけ止まるのはなぜか
結論から言うと、Claude Codeが使う抑止は「短命な caffeinate を次々に交代させる中継」で、交代の瞬間にアサーション(スリープを止める登録)が途切れます。画面が点いている間は別の登録が隙間を隠すので、気づけません。
#81832の報告者が、バージョン2.1.220の配布物を読み解いた内容は次のとおりです。
- macOSでは
caffeinate -i -t 300を起動する(-iはアイドルスリープの抑止、-t 300は300秒で解除) - 240秒ごとに、いま動いている
caffeinateをSIGKILLで止めてから、次のcaffeinateを起動する - 止める処理が先で、起動が後なので、アサーションが一瞬ゼロになる
-t 300 の終了は交代の240秒より後なので、放っておけば隙間は生まれません。隙間を作っているのは、明示的な強制終了です。これは公式の説明ではなく、報告者がバンドルを逆コンパイルして読んだ結果である点には注意してください。
画面が点いているときは見えない
OSの電源管理(powerd)は、画面が点いている間、自前で「ディスプレイが点いている間はスリープを防ぐ」という登録を持っています。caffeinate の交代で隙間ができても、この登録がスリープを止めます。
画面がオフになると、powerd はこの登録を手放します。残る保持者はClaude Codeの caffeinate だけなので、次の交代で登録がゼロになり、数秒後にアイドルスリープへ入ります。報告者の pmset -g log は、その並びをそのまま示しています(電源はバッテリー、sleep 1 の設定)。
| 時刻 | 出来事 |
|---|---|
| 15:51:08 | 出来事caffeinate が交代。ディスプレイ点灯中なので隠れる |
| 15:53:18 | 出来事ディスプレイがオフ。powerd の点灯中登録が解放される |
| 15:55:08 | 出来事次の交代で No Assertions(登録ゼロ) |
| 15:55:13 | 出来事5秒後に Idle Sleep へ |
| 16:02:59 | 出来事人が戻って操作し、ようやく復帰 |
CLIのプロセスツリー全体が眠るため、中継は自分で再起動できません。復帰するまで、抑止は戻りません。
一度露出すると、ほぼ毎回起きる
別のユーザーがM4 Pro(macOS 26.5.2)で1週間のログを数えた結果が、同じissueのコメントにあります。交代は342回で、そのうち画面オフ中が14回、14回のうち10回(71%)が5〜9秒以内のアイドルスリープに続きました。残りの328回は、画面点灯中の登録に隠れていました。
別のコメントは、交代で新しい caffeinate が同じ秒に起動していても眠ったと報告しています。powerd は最後の保持者が消えた時点でスリープの判断を始め、5秒の猶予(darkwakelinger)が切れると、その間に新しい登録が入っていても眠る、というのがそのコメントの読みです。つまり「交代を速くする」のでは足りず、「登録を絶対にゼロにしない」順序が必要になります。
自分のMacで同じことが起きているか確かめる
確認はログを見るだけで済みます。実行前にタスクを走らせておく必要はありません。過去のログから探せます。
# 電源状態ごとのスリープ設定(sleep の値が0以外か)
pmset -g custom
# 画面オフ・caffeinateの終了・スリープ移行を時刻順に拾う
pmset -g log | grep -E \
"Display is turned off|caffeinate|Entering Sleep"見る場所は3つです。
caffeinate command-line toolのClientDiedの行に、保持時間00:03:59と[System: No Assertions]が並んでいるか- その数秒後(報告では5〜20秒)に
Entering Sleep state due to 'Idle Sleep'が出ているか - 直前に
Display is turned offが出ているか
3つが揃えば、報告と同じ型です。00:03:59 は240秒で強制終了された caffeinate の保持時間で、自分で caffeinate を使っていない人なら、Claude Codeの子プロセスと見てよい目印になります。
sleep の値が 0 なら、そもそも自動スリープが無効なので、この現象は起きません。報告者は、MacBookの出荷時既定が電源アダプタ・バッテリーとも sleep 1 で、既定のままの機体は対象になると書いています。
再現を急ぐなら、pmset displaysleepnow で画面をすぐ消す方法が、コメントで紹介されています。交代は4分以内に来るので、そのときの pmset -g log で確認できます。
手元でできる回避策
公式の修正が出るまでの手段は、「Claude Codeの外から、途切れない登録を1本張る」ことに集約されます。コメントで提案された方法と、その限界を並べます。
caffeinateをCLIの寿命に結びつける
別のターミナルで、Claude Codeのプロセスが生きている間だけ保持する caffeinate を起動します。
# いちばん新しいclaudeプロセスに結びつける
caffeinate -i -w "$(pgrep -nx claude)"
# 複数セッションがあるときはPIDを指定する
pgrep -lx claude
caffeinate -i -w <PID>-w は、指定したプロセスが終わるまで待ち、終わったら登録を解放するオプションです。1本の長い登録が続くので、中継が交代してもゼロにはなりません。効いているかは pmset -g assertions で確かめられます。
もう1つの方法は、claude を caffeinate の配下で起動することです。caffeinate -di claude のようにコマンドを渡すと、そのコマンドが動いている間だけ登録が続くと、man caffeinate に書かれています。-d を付けるとディスプレイのスリープも止めるので、画面を消したい用途では -i だけにします。
設定でスリープ自体を止める
pmset -a sleep 0 で自動スリープを無効にする方法も、コメントで挙がっています。確実ですが、バッテリー駆動のMacを持ち歩くと、カバンの中で動き続けます。変更前に pmset -g custom の値を控え、作業が終わったら元に戻してください。
| 手段 | 効く範囲 | 注意 |
|---|---|---|
caffeinate -i -w <PID> | 効く範囲そのセッションの間だけ | 注意起動し忘れると効かない。蓋を閉じると眠る |
caffeinate -di claude | 効く範囲claude の実行中 | 注意-d は画面も点いたままにする |
pmset -a sleep 0 | 効く範囲全電源状態で恒常的に | 注意戻し忘れるとバッテリーを消費する |
落とし穴
蓋を閉じると、どれも効かない
caffeinate -i はアイドルスリープを止めるもので、蓋を閉じたときのスリープは止めません。コメントの報告者は、蓋を閉じても動かし続けるには pmset disablesleep が要り、その後に自分で戻す必要があると書いています。#81832の再現手順も、蓋を閉じない状況(画面ロックや画面の自動消灯)を対象にしています。
長いツール呼び出しの途中で眠ると、何が起きるか
ここまでは交代の一瞬の話でしたが、被害の大きさは別の要因で決まります。コメントには、症状の出方が3通りあります。
- 接続エラーで止まる: 戻ると
API Error: Connection closed mid-response. The response above may be incomplete.が出ている。別の報告ではYour computer went to sleep mid-responseという文言も出ており、CLIがスリープを検知して知らせる経路があるようです - 偽のタイムアウト: 10分のポーリングコマンドの途中で眠った例では、起きた直後に
Exit code 143 / Command timed out after 10m 0sが出ました。コマンドは凍結されていても、タイムアウトは実時間で進むため、起きていない間に失敗が確定します - 何も出ない: 2.1.280の報告では、約7.5分眠っていたのにエラーが残らず、ターンは正常終了しました。痕跡は
pmset -g logと、セッション記録の時刻のずれにだけ残ります
3つ目の報告者は、エラー文言の件数でこの問題を数えると過少になる、と指摘しています。自分のセッションを疑うときは、エラーが出ていなくても、不自然に長い所要時間を pmset -g log と突き合わせる価値があります。
ビルドやデプロイ、kubectl の状態監視のように1回のツール呼び出しが長い作業ほど、眠ったときの損失が大きくなります。報告者は、被害は交代の隙間(数秒)でなく、ツール呼び出しの長さで決まる、と整理しています。
入力待ちが30秒を超えても外れる
#81832の報告者は、もう1つの穴にも触れています。抑止はTUIの「busy」状態に連動していて、busyを抜けて30秒後に解除されます。したがって、ターンの途中でもユーザー入力を30秒以上待つ場面では、守られません。許可の確認待ちなどで長く止まる運用では、外からの caffeinate -w のほうが、Claude Code内蔵の抑止より広く覆います。
修正の状況と、バージョンの目安
報告者は、修正案として次の3つを挙げています。優先順に、プロセス内でスリープ抑止のAPIを直接保持する案、caffeinate -i -w でCLIの寿命に結ぶ案、起動を先にして終了を後にする入れ替え案です。入れ替え案は最小の修正で、登録が重なる分には害がありません。
コメントでは、この中継の構造が2.1.239、2.1.266、2.1.280のバンドルにも残っていると確認されています。別の報告者は、2.1.173では長時間の無人セッションで Idle Sleep が1度も出ず、2.1.259を使い始めた日から出始めたと書いています。報告者本人は「確認した全バージョンで存在する」としており、両者は一致しません。バージョンを戻して回避する前に、pmset -g log で自分の環境の事実を取るほうが確実です。
なお、v2.1.83のリリースノートには、終了後に caffeinate が残ってMacが眠れなくなる不具合の修正があります。Claude Code v2.1.83の変更点にまとめた件で、こちらは逆向き(眠れなくなる側)の症状です。
Windowsには、交代以前に抑止がない
Windowsの話は、#96679で別に報告されています。2.1.280の配布物を読んだ報告者によると、スリープ抑止のスポーン引数を返す分岐はmacOSだけで、それ以外のOSは null を返します。中継の起動も、null なら即座に何もしません。Linuxも同じ分岐で null に落ちる、と書かれています。
報告者は、管理者権限の powercfg /requests を、claude.exe を18プロセス起動し1セッションがターン実行中の状態で実行しました。全カテゴリが None. で、エージェントが動いている間、誰も保持していなかったとあります。
# 管理者として実行。ターン実行中に見る
powercfg /requestsmacOSと違い、交代の隙間は無く、抑止そのものが無いわけです。デスクトップアプリには「Keep computer awake while Claude works」という設定があり、ターン単位でスリープを止めるログが出る、という対比もissueに書かれています。CLIには同等の設定がありません。
Windows側の手元の対処は、スリープまでの時間を変えるか、作業中は電源要求を別の手段で保持するかです。スリープの待ち時間は powercfg /change standby-timeout-ac <分> のように分単位で変更できます(Microsoftのドキュメントの書式)。電源要求の読み方、Linuxの抑止、デスクトップアプリの症状は、Claude Codeでスリープできない原因 — Windowsの電源要求とLinuxの抑止が受けています。
Windowsには、ユーザーモードのプログラムが越えられない上限もあります。#96679が引用するMicrosoftのドキュメントによると、Modern Standbyのバッテリー駆動では、システム要求と実行要求はスリープタイムアウトの5分後に終了します。蓋を閉じる操作などユーザー操作によるスリープでは、要求は終了します。この上限は、アプリ側の修正が入っても残ります。
長時間タスクを任せる前の確認
Macで長時間タスクを無人で回すなら、画面オフ後に最初の交代で止まる可能性を前提に、次の流れを組むのが無難です。
pmset -g customでsleepの値を見る(0なら対象外)- 無人で回すセッションの横で、
caffeinate -i -wを張る - 翌朝、
pmset -g logでNo AssertionsからのIdle Sleepが出ていないかを見る - 長い作業は、止まっても再開できる形にしておく
4については、進捗をファイルに残して再開する方法をClaudeの長時間タスクをtests.jsonとprogress.txtで管理するで書いています。Remote Controlの放置切断は原因が別なので、Remote Controlが20分放置で切断される原因と回避策で確認できます。
まとめ
Macで画面オフ後に止まる症状は、240秒ごとの caffeinate 交代で登録がゼロになる瞬間に、OSが眠る構造として報告されています。修正されるまでは、外から caffeinate -i -w を1本張るのがもっとも副作用の少ない手段で、蓋を閉じる運用は別の設定が要ります。Windowsは交代以前に抑止が無いので、スリープの待ち時間を前提に計画を立てる必要があります。