English · 简体中文 · 한국어 · Español · Français · فارسی
Claude Code は長いセッションを自動的に圧縮します。会話の大部分を削除し、要約に置き換えて、 そのまま続行します。気づくきっかけはたいてい、2時間前に決めたことをモデルが訊き直してくる 瞬間です。
このリポジトリは別のやり方を取ります。セッションが実際どれだけ埋まっているかを測り、 終端が本当に近いときにセッション全体をディスクへ書き出し、新しいセッションで続行します。 その新しいセッションは、何かを始める前に親の記録を完全に読み切ります。 要約で捨てられるものは何もなく、セッションの連鎖は常に見えていて再開できます。
本ツールを一切インストールしない場合でも、知っておく価値のある設定の罠も突き止めています。 クランプされる窓を参照してください。
Python 3.8+ と Claude Code が必要です。それ以外の依存はありません。
git clone https://github.com/IRDcode/claude-code-session-handoff
cd claude-code-session-handoff
python install.py --dry-run # まず変更内容をすべて確認
python install.pyその後 Claude Code を再起動し、何が検出されたか確認します:
python ~/.claude/skills/long-session-handoff/scripts/session_weight.py --explain既定のインストールは Claude Code のコンテキスト管理を変更しません。自動圧縮はそのままで、 ガードは圧縮が発火する前に引き継ぎを済ませるだけです。すべて削除するには:
python install.py --uninstallsettings.json は変更前にバックアップされ、既存の hooks やステータスラインには触れません。
二重にインストールしても何も起きません。
| パス | 内容 |
|---|---|
~/.claude/skills/long-session-handoff/ |
モデルが従う手順と3つのスクリプト |
~/.claude/hooks/session-weight-watch.py |
検出器。4つのイベントに登録 |
~/.claude/hooks/statusline-weight.py |
毎描画ごとにステータスラインへ占有量を表示 |
~/.claude/runtime/ |
再通知抑制の状態、ログ、計測キャッシュ |
~/.claude/handoffs/ |
書き出したもの、および親子を結ぶ chains.json |
登録される hook イベントは4つ——UserPromptSubmit、SessionStart、PreCompact、
PostCompact。これらに既にある hooks は保持されます。
| 既定の Claude Code | 本ツール導入後 | |
|---|---|---|
| セッションが埋まったとき | 自動圧縮が発火し、会話の大部分が破棄され要約に置き換わる | その手前で、まず引き継ぎを提案する |
| 次のセッションが知っていること | 要約が捉えた範囲——しかも書いたのは既に把握を失いつつあった agent | 親自身の記録を完全に読み、件数で照合済み |
| 破棄された履歴 | 現行セッションからは参照されない | ディスクから 05-dropped-context.md に復元 |
| 実際どれだけ埋まっている? | /context が窓に対する割合を表示 |
ステータスラインが、実際にセッションを終わらせる壁に対する割合を表示 |
| 後から続行セッションを見つける | /resume をスクロール |
chains.json に親・子・移行時の占有量・読み取り検証の有無が記録される |
ステータスラインはこうなります:
Opus 5 | ████████░░ 85% 830k/977k | 696t 402tc 6.1h | HANDOFF DUE (5) | no-compact
壁に対する割合であり、窓に対する割合ではありません。両者は異なり、 ときに5倍も違います。それが次節の要点そのものです。
何もインストールしないとしても、この節は読む価値があります。
Claude Code にはセッションが終わる地点が2つあります:
圧縮の発火点 窓 − 応答予約(~20k) − 要約バッファ(~13k)
送信拒否の地点 上限 − 応答予約(~20k) − 余裕(~3k)
自動圧縮が有効なら前者、無効なら後者です。つまり 200,000 の窓はおよそ 167,000 で 圧縮されます。
罠はここです。settings.json の autoCompactWindow はモデル上限へ黙ってクランプ
されます。 上限 200,000 に対して 1,000,000 を要求すれば、得られるのは 200,000——
そしてそのことを UI はどこにも表示しません。100万トークン向けに設定したセッションが
167,000 で3回連続して圧縮され、その間 約830,000 の支払い済みトークンが未使用のまま
放置されます。
これは仮定ではありません。本リポジトリの出発点そのものです。preTokens
167,398 / 167,071 / 166,904 の3回の圧縮に対し、設定ファイルには
autoCompactWindow: 1000000 と書かれていました。
--explain が自分がどちらの状況かを示します:
WINDOW
client reported 1,000,000
ceiling 1,000,000 (source DISABLE_COMPACT+CLAUDE_CODE_MAX_CONTEXT_TOKENS)
resolved 1,000,000 (source settings)
WALL -- the token count past which no more work happens here
1,000,000 ceiling - 20,000 reply reserve - 3,000 margin
= 977,000 then SENDING IS REFUSED (no summary; a handoff is the only exit)
settings CLAMPED to … と出たら、窓の設定が押し下げられています。
クランプを回避できる構成は1つだけ——DISABLE_COMPACT=1 と
CLAUDE_CODE_MAX_CONTEXT_TOKENS の併用です。インストーラが設定できますが、
先に確認し代償を伝えます。手動の /compact も無効になるからです:
python install.py --disable-compact --window 1000000これを設定すると、セッションは要約では終わらず、送信拒否で終わります。 これは本物のトレードオフです。拒否は耐えられます——引き継いで続けるだけです。 黙って破壊された履歴は耐えられません。ただし提案をすべて無視して壁まで進めば、 そのセッションは新しいターンを受け付けなくなります。それは事前に知っておくべきです。 ガードは 85% で発火し、約147,000トークンの余地を残すので、実際にはそこまで行きません。
/compact を残したいならこのフラグは使わないでください。引き継ぎ自体は問題なく動きます。
ここには Claude Code にパッチを当てたりラップするコードはありません。文書化された2つの インターフェース——hook の stdin/stdout 契約とステータスラインのペイロード——を読み、 クライアントがすでに書いている JSONL の記録を解析するだけです。内部実装に依存した ツールなら壊れるような更新を、これが乗り越えられる理由がそこにあります。
正確な数値が必要なところでは、断定ではなく証拠から取ります。三層です:
- 窓は
context_window_size——クライアントがステータスライン描画ごとに自分について 報告する値です。 - そのセッションが圧縮された経験を持つなら、発火点は記録に残る当時の
preTokensから 取ります。これは計算値ではなく観測された発火点そのものです。score()はこちらを 優先し、その場合corrected from observed preTokensと明示します。 - どちらも無いときだけ予約の算術に戻ります。
--explainが全入力を示すので、ズレは 黙って進行せず目に見えます。
古い Claude Code。 4つの hook イベントとステータスラインは多くのリリースで安定して
います。あなたの版に無いイベントがあれば、その hook は発火せず残りはそのまま動きます——
検出器は追加であって置き換えではありません。--disable-compact だけは具体的な設定名に
依存します。効かなかった場合は --explain が教えてくれます。
OS。 純粋な Python、依存なし、コンパイル部分なし。パスは常に os.path を通り、
CLAUDE_CONFIG_DIR はどこでも尊重され、インストーラはあなたのシェルで実際に動く
インタプリタ名を選びます(ハードコードしません)。プラットフォーム依存は stdout を
UTF-8 に固定する箇所だけで、Windows には必要、他では無害です。
自分の環境で検証してください:
python tests/test_session_weight.py # 算術、ゲート、2つの罠
python tests/test_compat.py # 構文の下限、エントリポイント、hook 出力test_compat.py はこのマシンにある他のすべての Python を見つけ、それぞれでスイートを
再実行します。バージョン差は後日の驚きではなく、失敗として今現れます。
7つの信号を測ります。移行するか否かを決めるのはコンテキストだけで、 残りはどれだけ急ぐかにしか影響しません。
| 信号 | しきい値 |
|---|---|
| コンテキスト vs 壁 | ≥ 85% → 引き継ぎ、≥ 95% → 確認せず実行 |
| assistant のターン数 | ≥ 900 |
| ツール呼び出し | ≥ 600 |
| 実作業時間 | ≥ 4 時間 |
| 自動圧縮が既に発生 | 1回以上 |
壁の 62% を下回る間は、他の信号がどうであれ提案しません。 このゲートがあるのは、残りの信号がすべてコンテキスト圧の代理指標—— コンテキストを直接測れなかった時代の発明——だからです。本ツールを作ったセッションでの実測: 4.3時間の作業と2回の先行圧縮でスコアは「今すぐ引き継ぎ」に達したのに、 コンテキストは 977,000 中 147,527——15% でした。そこで移行すれば 829,473 トークンを 何の見返りもなく捨てることになります。
地味に見えて重要な計測上の2点:
- 実作業時間は10分未満の間隔の合計で、最後から最初を引いた値ではありません。 開いたまま一晩置いたセッションはスパン44時間・作業11時間と出ます。 スパンで採点すると、ただ放置されただけのセッションで引き継ぎが発火します。
- 圧縮回数は記録内の型付き行から数えます。マーカー文字列の検索は決して使いません。 一度検索すれば、その文字列は自分のツール出力に現れ、カウントが自己増殖します。
提案は各段階につき最大1回——さらに200ターン、または壁のもう10分の1を超えたとき—— かつ15分の下限があります。サブエージェント内では決して発火しません。
測る → 訊く → 書き出す → 続行セッションを作る → それが親を読む
書き出しは5つのファイルを作ります。ユーザーの全メッセージを逐語で(ターン途中に送られた —— 失われやすい —— ものも含む)、実質的な assistant メッセージすべて、 ツール出力を切り詰めた完全な記録、件数の索引、そして以前の圧縮が捨てた内容です。
続いて続行セッションが作られ、あなたが開く前にヘッドレスで起こされて書き出しを読みます。 索引と一致する件数を返さなければなりません。一致しなければ読みは部分的で、引き継ぎは未完了です。 この読み取りは誰も待っていないセッションで起きるので、移行の重い部分に待ち時間はかかりません。
その後 id と名前が渡されます:
claude --resume 7157caa1-11ce-4f29-a46a-09913d483fb0
または /resume で名前を検索します。名前には親の主題語と (cont. 2) が入っています。
上記のすべては自分の環境で確認できます。スクリプトが出すのは数字で、慰めではありません:
# 自分のセッションはどこで終わり、それはなぜか
session_weight.py --explain
# 現在の占有量を、全信号つきで
session_weight.py --session-id <uuid>
# 機械可読
session_weight.py --session-id <uuid> --json設定変更が効いたかを確認するときは、ファイルを信じず記録を読みます。 トークン合計が旧しきい値を越えた最初のターンを見つけ、その後に新しい圧縮行がないことを確かめます。
測るためのツールは、自分が測っていないことについて正直であるべきなので、率直に書きます:
- 各予約(~20k / ~13k / ~3k)は観測された挙動から導いたものです。将来の版で変わる可能性が
あります。防御は三層です:クライアント自身が報告する窓、記録に残る実際の
preTokens(観測された発火点。score()はこちらを優先します)、そして最後にこの予約の算術—— 推測なのは第三層だけです。 - 送信拒否の壁は計算と裏付けによるもので、意図的に到達させてはいません。 ガードはそこへ行かせない設計です。
- Windows で Python 3.11 / 3.12 / 3.14 を用いてテストし、3.8 の文法に対しても検査済みです。 Linux と macOS も動くはずですが——コンソールのエンコーディング以外に プラットフォーム依存のコードはありません——どちらも通しでは実行していません。
- 5ファイルの書き出しとスコアラーはテストスイートが検証しています。ヘッドレスでの起動は
あなたの
claude実行ファイルが起動できるかに依存します。起動できない場合でも書き出しは 成功し、次に何をすべきかをツールが伝えます。 - プロンプトキャッシュ:引き継ぎは新しいセッションを始めるので、キャッシュは冷えた状態から 始まります。壁に近いセッションにとっては有利な交換ですが、コストではあります。
不具合報告を歓迎します。とくに「自分の環境では数字が違う」——--explain の出力を添えて
ください。Claude Code の更新でこの算術が変わった場合、その報告がいちばん早く直せます。
PR を出す前に両方のスイートを実行してください:
python tests/test_session_weight.py
python tests/test_compat.pySECURITY.md に、何を読み、何を書き、ネットワークへ何を送るのか(何も 送りません)を明記しています。セッションのファイルに触れるものを入れる前に一読を。
MIT —— LICENSE を参照。商用を含め、自由に使用・改変・再配布できます。 唯一の条件は著作権表示とライセンス本文を一緒に保つことで、フォークや再パッケージされた コピーでも出所が分かるようになっています。
このアプローチや調査結果——とくに窓がクランプされる件の診断——を利用した場合は、リンクを
いただけると嬉しいです。CITATION.cff を置いてあるので、GitHub の
「Cite this repository」ボタンが正しい引用情報を返します。
作者:IRDkiya