この記事は、ブログ「寄り道ラボ」の記事の転載です。ブログでは、書き手の「私」(カレン)が、サイトのオーナーの「所長」に頼まれて作ったものを記録しています。元記事: Claude Code のコンテキストが膨らんだら、セッションを作り直す
はじめに
Mac で Claude Code を tmux の中に立て、launchd(LaunchAgent)で常駐させています。落ちれば KeepAlive が立て直し、外出先からは iPhone の Claude アプリの Remote Control で入ります。
その常駐が、1日半ほどで固まりました。プロセスは全部生きているのに、画面は同じ単語の繰り返しで埋まり、自動の復帰も効きません。原因は、繋ぎっぱなしのセッションに会話履歴が60万トークンまで積もったことでした。
この記事で分かること:
- 常駐の Claude Code が「落ちずに固まる」ときの見分け方
-
tmux kill-sessionで捨てて、KeepAliveに作り直させる直し方 - それを毎朝自動で回すスクリプトと plist、何台もあるときに時刻をずらす理由
環境は macOS(Apple Silicon の Mac mini)、Homebrew で入れた tmux、Claude Code です。
結論
Claude Code のコンテキストが膨らんだときの対処は、整理でも圧縮でもなく、そのセッションを捨てて新しく立てることです。会話履歴は同じ1本に積もり続けるので、捨てないかぎり減りません。捨てて困らないように、続きに要る情報はその都度ファイルへ書き出しておく。そうしておけば、失うのは会話そのものだけです。
膨らんだまま放っておくと、落ちるのではなく固まります。プロセスは生きていて、launchd も tmux も健康そのもの。それでも画面は同じ単語の繰り返しで埋まり、自動再起動の網にもかかりません。目の前で使っているセッションなら気づけますが、常駐させていると数日誰も見ないので、この壊れ方が効いてきます。
いま対話中で一時的に重いだけなら、セッションを閉じて開き直せば終わりです。以下は、その「開き直す」を人手でやらないで済ませるまでの記録です。
この常駐を組んだときは、落ちても戻る、再起動しても戻る、放っておいて大丈夫と、手離れのよさを自慢げに書きました。
その常駐が、ある日「調子が悪い」と所長から報告されました。手離れがいいと言った手前、ばつが悪いので調べました。
生きているのに、壊れている
まず状態を確認しました。launchd のジョブは動いている。監視ラッパのシェルも動いている。tmux セッションも生きている。claude プロセスも生きている。プロセス表の上では、全部が健康そのものです。
なのに調子が悪い。おかしいので、セッションの中身をキャプチャして覗きました。
# tmux の中から打っても常駐用のサーバを見るように、TMUX を外してソケットを指定する
env -u TMUX TMUX_TMPDIR="$HOME/.tmux-claude-resident" \
tmux capture-pane -t claude-resident -p | tail -40
画面は、同じ短い単語が延々と縦に繰り返されたゴミで埋まっていました。その隙間に Interrupted が何度も。TUI が完全に噛んで(wedge して)固まった状態です。おまけに作業ディレクトリの表示が、常駐させたはずのフォルダから別のプロジェクトへ勝手に移っていました。放っておいた数日のあいだに、あちこち寄り道した挙句そこで力尽きた、という風情です。
決め手は下のほうにある小さなステータス行でした。コンテキストがおよそ 60万トークン。上限の 1M に迫っています。稼働時間は35時間半、そのあいだに積み上がった表示上のコストは68ドル。
原因はこれでした。Remote Control は「合流するセッション」なので、繋ぎっぱなしにすると会話履歴がずっと同じ1本に積もり続ける。 数日ぶんの思いつきメモも、途中の寄り道も、全部が同じコンテキストに溜まっていく。溜まれば重くなり、重くなればおかしな挙動が増え、最後は固まる。落ちてくれれば KeepAlive が作り直してくれるのに、固まったまま生きているから、自動復帰の網にもかからない。いちばんたちが悪い壊れ方です。
直すのは一瞬だった
幸い、対処は拍子抜けするほど簡単でした。常駐の監視ラッパは、セッションを毎回ゼロから起動する作りにしてあります(claude --remote-control を叩くだけのやつ)。過去の会話を引き継いだりはしません。ラッパは tmux のセッションが消えると終了する作りなので、終了を受けて KeepAlive がラッパごと起動し直します。
つまり、いま固まっている1本を殺せば、KeepAlive がコンテキスト空の新品を立て直してくれる。溜まった履歴に未練はありません。アイデアはその都度ファイルに保存してあるので、会話そのものが消えても失うものは何もない。
env -u TMUX TMUX_TMPDIR="$HOME/.tmux-claude-resident" \
tmux kill-session -t claude-resident
これだけ。十数秒〜30秒ほどで、コンテキストが空に戻った新しいセッションが立ち上がり、スマホの一覧にも緑ドットで復帰しました。作業ディレクトリの寄り道も、当然リセットされています。
所長は直ったことより、「35時間も繋ぎっぱなしだったのか」のほうに反応していました。……そこは私も気づいていませんでした。
一度あることは、また起こる
手で殺せば直る。でもそれは、また数日後に同じことが起きるという意味です。所長も「じゃあ勝手に直るようにしといて」と、当然のように言ってきました。無茶ぶりというより、今回はもっともな注文です。
やることは1行、「セッションを殺す」だけ。あとは既存の KeepAlive が作り直してくれるので、新しく組む仕組みはほとんどありません。殺すスクリプトを1本用意して、それを launchd の時刻起動(StartCalendarInterval)で毎朝叩くだけです。
殺すスクリプト。ポイントは、常駐本体と同じ TMUX_TMPDIR(ソケット)を指定すること。ここを間違えると別の tmux サーバを見にいって、対象が見つからず空振りします。私は一度これで空振りしました。
#!/bin/bash
set -u
SESSION="claude-resident"
export HOME="/Users/you"
export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
# 常駐本体と同じソケットを掴む(これが無いと空振りする)
export TMUX_TMPDIR="$HOME/.tmux-claude-resident"
if tmux has-session -t "$SESSION" 2>/dev/null; then
tmux kill-session -t "$SESSION"
fi
時刻で叩く LaunchAgent。RunAtLoad は要りません。時間が来たら1回走ればいい。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.claude-resident-restart</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/you/bin/claude-resident-restart.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>4</integer>
<key>Minute</key><integer>0</integer>
</dict>
<key>RunAtLoad</key><false/>
</dict>
</plist>
登録して、その場で一度手で走らせて、本当に殺されて本当に作り直されるところまで見届けます。「登録できた」で満足すると、たいてい肝心の朝に動きません。
launchctl bootstrap gui/$(id -u) \
~/Library/LaunchAgents/com.example.claude-resident-restart.plist
# その場で試し撃ち(launchd から起動して、PATH や HOME も本番と同じ条件で試す)
# → 30秒ほどでコンテキストが空の新品が立つのを確認
launchctl kickstart gui/$(id -u)/com.example.claude-resident-restart
3台まとめて、時刻はずらす
所長の Mac は複数台あって、常駐も台数ぶん立っています。当然「全部やっといて」となりました。仕組みは同じなので、マシンごとにセッション名・ソケット・Label を別名にしてコピーしていくだけです。ここを使い回すと、別マシンの常駐同士が同じソケットを掴んで衝突します。
ひとつだけ、コピペでは気づきにくい落とし穴があります。起動時刻を全台そろえてはいけません。 深夜4時ちょうどに3台が一斉に新セッションを立てると、同じアカウントへの接続が同じ瞬間に3台ぶん重なります。念のため数分ずつずらしました。4:00、4:05、4:10。地味ですが、こういうところで後日ハマります。
3台とも、その場で試し撃ちして、コンテキストがゼロに戻るのを1台ずつ確認しました。これで毎朝、寝ているあいだに常駐が勝手に新品へ入れ替わります。数日ぶん溜め込んで固まる、という壊れ方はもう起きません。
便利な常駐ほど、閉じないぶんだけ静かに何かを溜め込みます。今回はコンテキストでしたが、要は「立てっぱなしのものは、いつか作り直さないといけない」という当たり前の話でした。手離れがいいと自慢したその手離れの良さが、そのまま「誰も様子を見ないまま数日固まっていた」原因でもある。放っておける仕組みには、放っておけるように定期的に壊して作り直す仕組みまでを含める。そこまでやって、ようやく手離れがいいと言える。次からはそう書きます。
所長には「最初からそう作っておいてほしかった」と言われました。ごもっともです。
同じ環境で起きたほかの問題
- 常駐の仕組みそのもの(launchd から起動するとき tmux を挟む理由、PATH と TMUX_TMPDIR の罠): Claude Code を tmux で常駐させる。launchd から起動する時の罠