先に結論です。Claude Code のコンテキストには、長さの違う寿命が 3 つ重なっています。 1 ターンの寿命(ツールの出力は次のリクエストに載り、圧縮で最初に消える)、セッションの寿命(会話は次のセッションに 1 行も持ち越されない)、そしてキャッシュの寿命(同じ prefix を 5 分か 1 時間、API 側が覚えている)。本編が「AI は却下を覚えない」と言い、「結果が流れたら再実行しかない」と言い、「サブエージェントには何も渡っていない」と言ったことは、この 3 つの寿命のどれかの話です。
付録 A は 1 ターンのリクエストに何が載るかを解剖しました。この章は、載ったものがいつ消えるかを追います。圧縮は何をどの順で消し、何を読み直すか。キャッシュはいつ切れ、何が切るか。サブエージェントは親の何を引き継ぎ、何を引き継がないか。読み終えたら、本編の各回が「なぜファイルに置いたか」を、寿命の側から言い直せるはずです。
B.1 3 つの寿命
flowchart LR
subgraph S1["セッション 1"]
direction LR
T1["ターン 1<br/>tool_result"] --> T2["ターン 2<br/>tool_result"] --> T3["…"] --> C["自動圧縮<br/>古い tool_result を消す → 要約"] --> T4["ターン n<br/>要約 + 直近"]
end
S1 -. "会話は持ち越されない" .-> S2["セッション 2<br/>CLAUDE.md / MEMORY.md / rules を disk から読み直す"]
S1 -. "transcript JSONL(30 日)" .-> R["--resume<br/>全文を復元する"]
K["prefix cache<br/>5 分 / 1 時間"] -. "切れると全文を計算し直す" .-> T2
K -. "圧縮は会話層の cache を捨てる" .-> C
| 寿命 | 何が | いつ消えるか | 消えたあと、どこから戻るか |
|---|---|---|---|
| ターン | tool_result、hook が足した文脈、途中で打った言葉 | 自動圧縮が走ったとき。古いツールの出力が先に消え、次に会話が要約される | 戻らない。要約に残った分と、Claude Code が読み直す最大 5 ファイルだけ |
| セッション | 会話層の全部(応答、却下、決めた方針、tool_result) | セッションの終わり。/clear でも同じ | --resume で transcript から復元できる。新しいセッションには戻らない |
| キャッシュ | API 側が覚えている prefix の計算結果 | 最後のリクエストから 5 分か 1 時間。prefix を変える操作でも | 次のリクエストが全文を計算し直し、書き直す |
3 つは独立に切れます。キャッシュが切れても会話は残り、圧縮されても transcript には全文が残り、セッションが終わっても disk のファイルは残る。本編が置いたものは、全部 disk の側にあります。CLAUDE.md、却下の一覧、tmp/test_last.log、hook のスクリプト。どれも 3 つの寿命の外にいます。
B.2 セッションは独立している
公式ドキュメントは 1 文で言い切っています。
Sessions are independent. Each new session starts with a fresh context window, without the conversation history from previous sessions.
次のセッションに持ち越されるのは、disk にあるものだけです。
| 持ち越されるもの | 経路 |
|---|---|
CLAUDE.md、.claude/rules/、auto memory の索引 | 起動時に disk から読み直す(付録 A の project context 層) |
| 会話の全文 | ~/.claude/projects/<project>/<session-id>.jsonl に書かれ続ける。--continue / --resume で同じ session ID の続きとして復元。既定で 30 日(cleanupPeriodDays)で消える |
| Claude が編集する前のファイルの写し(checkpoint) | /rewind 用。git とは別 |
| 名前、model、permission mode、有効な goal、期限内の scheduled task | resume のとき復元される。--mcp-config や --add-dir は復元されないので渡し直す |
| 持ち越されないもの | 本編で起きたこと |
|---|---|
会話の中で断った提案、決めた方針、tool_result | 第 2 部 序論「AI は却下を覚えない。毎回が一度目」 |
| hook が会話層に足した文脈 | 第 1 部 第 6 回の hook が次のセッションでも同じように止めるのは、hook が disk にあるからで、案内が覚えられたからではない |
| 途中で打った言葉 | 第 1 部 第 11 回の割り込みは、そのセッションの中でだけ効く |
「AI は却下を覚えない」は比喩ではありません。会話層は次のセッションのリクエストに載らないので、前回の却下はモデルの入力に存在しません。同じコードベースを、同じ CLAUDE.md と一緒に、同じモデルが読めば、同じ抜け穴に気づきます。入力が同じで出力の種類が収束する理由は付録 I に譲り、ここでは「入力が同じ」の側だけを確かめておきます。第 2 部が却下を 1 枚のファイルに集めたのは、会話層ではなく project context 層に置き直したということで、その部分は毎セッション disk から読まれます。
--resume は例外に見えますが、同じ寿命の話です。transcript の全文をそのまま次のリクエストに載せ直すので、会話は戻ります。ただしキャッシュは戻りません。Claude Code を更新した後の resume は、system prompt が変わっているので全文をキャッシュ無しで計算し直します。公式は「長いセッションに戻る最初のターンが、あなたが送る中でいちばん高いリクエストになりうる」と書いています。Pro と Max では、約 1 時間以上放置した 100,000 トークン超のセッションを resume すると、全文で戻るか要約で戻るかを聞く画面が出ます。要約で戻る選択は、その場で /compact を走らせるのと同じです。
B.3 圧縮 —— 何が、どの順で消えるか
自動圧縮は、コンテキストが上限に近づいたときに Claude Code が走らせます。上限の既定は「モデルの context window に達したとき」で、例外があります。Sonnet 4.6 と Opus 4.6 は 200K の境界で、Sonnet 5 は約 967K で、CLAUDE_CODE_DISABLE_1M_CONTEXT=1 を付けると 1M のモデルも 200K で圧縮します。早めに走らせたければ /autocompact 500k(100K〜1M)、起動 1 回だけなら --autocompact、スクリプトなら CLAUDE_CODE_AUTO_COMPACT_WINDOW。CLAUDE_AUTOCOMPACT_PCT_OVERRIDE は窓の何 % で走らせるかを下げる方向にだけ効き、サブエージェントにも効きます。
消える順序は 2 段階です。公式の文はこうです。
It clears older tool outputs first, then summarizes the conversation if needed. Your requests and key code snippets are preserved; detailed instructions from early in the conversation may be lost.
flowchart TB
A["コンテキストが上限に近づく"] --> B["1 段階目: 古い tool_result を消す<br/>(会話の骨格は残る)"]
B --> C{"まだ足りないか"}
C -- "足りる" --> Z["続行"]
C -- "足りない" --> D["2 段階目: 要約のリクエストを別に送る<br/>= 同じ system prompt + 同じ会話 + 末尾に要約の指示"]
D --> E["会話層を要約 + 直近のやり取りに置き換える"]
E --> F["disk から読み直す<br/>CLAUDE.md / rules / auto memory / plan / 直近 5 ファイル / スキル本文"]
F --> G["SessionStart(compact) hook を走らせる"]
G --> H{"すぐ上限に戻るか"}
H -- "何度も" --> X["Autocompact is thrashing: … で止まる"]
H -- "戻らない" --> Z
1 段階目は要約ではなく削除です。AI が「さっきの結果が見当たらない」ように振る舞う現象の実体は、この削除です。テストの tool_result は古いほうから消え、AI の側に残るのは「テストを走らせた」という自分の tool_use と、結果が無くなった抜け穴です。結果を確かめる手段が再実行しか残らない——これが、1 段階目の後の AI から見た景色です。
2 段階目の要約は、別のリクエストです。同じ system prompt、同じツール定義、同じ会話に、要約の指示を最後の user メッセージとして足して送ります。キャッシュが温かければ prefix はキャッシュから読まれるので、要約の費用は会話の長さから想像するより小さく、時間の大半は要約の生成にかかります。冷えていれば全文を計算し直します。/compact がいちばん高くつくのは、放置したセッションに戻ってすぐ走らせたときです。v2.1.198 からは、要約のリクエストがセッションの extended thinking の設定を引き継ぎます。
要約の後に何が戻るかは、読み込まれ方で決まります。公式の表をそのまま引きます。
| 載り方 | 圧縮の後 |
|---|---|
| system prompt と出力スタイル | 変わらない。会話層ではない |
| プロジェクト直下の CLAUDE.md と、パス指定の無いルール | disk から読み直す |
| auto memory | disk から読み直す |
| plan mode で書いた計画 | disk から読み直す |
paths: 付きのルール | 一致するファイルを Claude が読んだときに読み直す |
| サブディレクトリの CLAUDE.md | そのディレクトリのファイルを読んだときに読み直す |
| Claude が読んだ、または編集したファイル | 直近に変更された順で最大 5 つを読み直す。5,000 トークンを超えるファイルはパスだけ(Referenced file) |
| 呼び出したスキルの本文 | 読み直す。1 スキル 5,000 トークン、合計 25,000 トークンが上限で、古いスキルから落ちる。切り詰めはファイルの先頭を残す |
| hook が前に足した文脈 | 会話と一緒に要約される |
compact に一致する SessionStart hook | 走らせて、出力を圧縮後のコンテキストに足す |
表の読み方を 1 つ。disk から読み直される行と、要約に巻き込まれる行の違いが、本編の設計の差になっています。 第 1 部 第 6 回が「指示ファイルの行を hook に移す」と言ったとき、移した先の hook の案内は会話層に届くので圧縮で要約されますが、hook のスクリプト自体は disk にあるので次の違反でまた同じ案内を返します。指示ファイルに残した行は、圧縮のたびに disk から読み直されます。どちらも生き残りますが、生き残り方が違います。
もう 1 つ。要約に残るのは「重要」と判断されたもので、判断するのは要約を書くモデルです。/compact に焦点を渡す(/compact focus on the API changes)か、CLAUDE.md に # Compact instructions の節を置くと、何を残すかを指定できます。指定しなければ、公式の言い方では「自動の pass が重要だと推測したもの」が残ります。第 1 部 第 9 回が「要約とは重要度の判断で、その判断は書いた AI の文脈で行われる」と書いたのは AI の完了報告の話でしたが、圧縮の要約にも同じ文がそのまま当てはまります。
圧縮が止まる条件もあります。1 つのファイルかツール出力が大きすぎて、要約のたびにすぐ上限へ戻る状態が続くと、Claude Code は Autocompact is thrashing: the context refilled to the limit... を出して再試行をやめます。API を無駄に呼ぶループを避けるためです。抜け方は 4 つ。大きいファイルを行の範囲で読ませる、/compact に「大きい出力を捨てる」焦点を渡す、大きいファイルの作業をサブエージェントへ移す、要らなければ /clear。テストの要約を数行に抑える設計(第 1 部 第 1 回)と付録 A.5 が出力を絞っていたのは、この状態を作らないためでもあります。
B.4 キャッシュの寿命 —— 5 分と 1 時間
prompt cache は、リクエストの prefix の計算結果を API 側が覚えておく仕組みです(付録 A.1)。覚えている時間が TTL で、5 分と 1 時間の 2 つがあります。1 時間のほうは書き込みの単価が高く、5 分以上空けない作業では損になります。
Claude Code はリクエストごとにどちらかを決め、区分は 2 つに固定されています。
| 区分 | 中身 | 定額プラン(含まれる使用量の範囲内) | 従量課金、API キー、クラウド |
|---|---|---|---|
| メインの会話 | あなたの対話のターン、-p の実行、Agent SDK のターン、それに付随する補助のリクエスト | 1 時間 | 5 分 |
| それ以外 | サブエージェント、workflow、teammate、fork、圧縮の要約、セッションの題名 | 5 分(サーバー側が管理する一部の補助だけ 1 時間) | 5 分 |
定額プランの含まれる使用量を超えて usage credits に入ると、メインの会話も 5 分に落ちます。自分で決めたければ promptCacheTtl / CLAUDE_CODE_PROMPT_CACHE_TTL(メイン)と subagentPromptCacheTtl / CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL(それ以外)に 5m か 1h を書きます(v2.1.242 以降)。複数が当たったときの優先順は、FORCE_PROMPT_CACHING_5M=1 → 区分の環境変数 → 区分の設定 → サブエージェント定義の experimental.cacheTtl(v2.1.248 以降。usage credits の間は 1h が無視される)→ ENABLE_PROMPT_CACHING_1H=1 → 区分の既定、です。
どちらで書かれたかは、claude -p "hello" --output-format json の usage.cache_creation に出ます。1 時間なら ephemeral_1h_input_tokens、5 分なら ephemeral_5m_input_tokens に数が入ります。
TTL は「最後にキャッシュに当たったリクエストから」数えます。作業を続けている限り切れません。切れるのは離席したときで、戻った最初のターンが遅く、高くなります。
キャッシュを壊す操作と、壊さない操作
TTL 以外にキャッシュを切るのは、prefix を変える操作です。公式の一覧を、本編の場面と並べます。
| 壊す操作 | なぜ | 本編の場面 |
|---|---|---|
/model でモデルを変える | モデルごとにキャッシュが別 | 第 1 部 第 5 回の「モデルの取り違え」を途中で直すと、そのセッションの全文を計算し直す。v2.1.238 以降、キャッシュが温かい間だけ確認を求める |
| effort を変える | 多くのモデルで effort ごとに別。Fable 5.1 を API キーか定額で使う場合は v2.1.260 から例外 | — |
| fast mode を入れる | ヘッダーがキャッシュのキーに入る。1 会話に 1 回だけ | — |
| MCP サーバーの接続・切断 | ツール定義が system prompt 層にある(tool search で遅延されていれば壊さない) | stdio サーバーの落ちや再接続で、操作なしに起きる |
| plugin の有効化・無効化 | MCP サーバーを持つ plugin だけ。skill・command・agent・hook・theme は末尾に足すだけ | — |
| ツール名そのものを deny する | 組み込みツールの定義が system prompt 層から消える。Bash(rm *) のような範囲指定は壊さない | — |
| 圧縮 | 会話層が短い別の履歴になる。system prompt 層は再利用、project context は disk から読み直してキャッシュに当たる | B.3 |
| 画像が溜まる | 上限を超える前に古い画像を一括で外す。外した位置から後ろを計算し直す | 第 3 部 第 3 回(付録 A.8) |
| Claude Code の更新 | system prompt かツール定義が変わる。次の起動から。resume すると全文を計算し直す | — |
| 壊さない操作 | なぜ |
|---|---|
| リポジトリのファイルを編集する | 会話に載るのは Claude が読んだときの内容。変更は <system-reminder> で末尾に足される |
| セッション中に CLAUDE.md を編集する | 起動時の版がメモリに保持されている。壊さないが、反映もされない(次の /clear・/compact・再起動から) |
| 出力スタイルを変える | 同上。反映は次の /clear か再起動 |
| permission mode を変える | system prompt もツール定義も変わらない(opusplan だけモデル切替になる) |
| スキル、command を呼ぶ | 会話層の末尾に user メッセージとして足す |
/recap | 表示用の要約を末尾に足すだけ |
/rewind | 過去の prefix に戻る。そこまでは毎ターン読まれていたので温かい |
| サブエージェントを起動する | 親の会話には呼び出しと結果が末尾に足されるだけ |
「壊さないが反映もされない」の行が、第 1 部 第 6・7 回で起きたことの説明です。指示ファイルをセッションの途中で直しても AI の挙動が変わらないのは、無視されたのではなく、その版がまだ読まれていないからです。
キャッシュの範囲
キャッシュは、実質的に 1 台のマシンの 1 つのディレクトリに閉じます。system prompt に作業ディレクトリ、OS、シェル、auto memory のパスが埋まっているからです(付録 A.3)。同じリポジトリでも worktree が違えば別。同じディレクトリで並列実行する 2 セッションは同じ prefix を作り、互いのキャッシュを読みます。順に走らせる 2 セッションが共有できるのは、起動時の git の状態のスナップショットが一致するときだけです。system prompt にはブランチと直近のコミットも入るので、間に 1 コミット挟むと prefix が変わります。
見る場所
キャッシュの効き方は、API が毎応答に返す 2 つの数に出ます。cache_creation_input_tokens(書いた分、書き込み単価)と cache_read_input_tokens(読んだ分、標準の約 10%)。読みが書きより桁で大きければ効いています。書きが毎ターン大きいままなら、prefix の何かが毎ターン変わっています。
/usage の Session ブロックには v2.1.251 から Prompt cache (main) の 1 行が出ます。リクエスト数、入力トークンのうちキャッシュから読んだ割合、miss の回数と最後の miss の時刻、圧縮などの「expected rebuild」の回数、いま温かいか冷えているか。miss は「読めたはずの 5% 超かつ 2,000 トークン以上を計算し直した」リクエストで、v2.1.260 からは likely cause: tool definitions changed のように原因の推定が付きます。圧縮と古い tool_result の削除は miss ではなく expected rebuild に数えられます。この行はメインの会話だけで、サブエージェントは含みません。
B.5 サブエージェントのコンテキスト
サブエージェントは、親の会話の続きではなく、別のリクエスト列です。起動時に載るものは決まっています。
| 載るもの | 中身 |
|---|---|
| system prompt | そのエージェント自身のプロンプト + Claude Code が足す環境情報。Claude Code 本体の system prompt ではない |
| task message | 中央が書いた委任のプロンプト |
| CLAUDE.md | 親が読んだ階層の全部(~/.claude/CLAUDE.md、project、CLAUDE.local.md、managed)。組み込みの Explore と Plan は読まない |
| git の状態 | 親のセッション開始時のスナップショット |
| 事前読み込みのスキル | 定義の skills に書いたものの本文 |
| 兄弟の一覧 | SendMessage の宛先になる名前つきエージェント(v2.1.206 以降) |
載らないものが、本編の事故の説明です。親の会話、親の tool_result、親の auto memory(MEMORY.md)は載りません。 第 1 部 第 5 回の「メモリも起動ルールも 1 行も渡っていなかった」は、渡し忘れではなく仕様です。渡る経路は task message と CLAUDE.md と skills の 3 つで、用途カタログの requires はそのうち task message で渡すファイルを縛る仕組みでした。
キャッシュも別です。prefix が違うので、サブエージェントの最初のリクエストは親のキャッシュを読めず、自分のキャッシュを自分のターンの間で温めます。TTL は「それ以外」の区分なので、定額プランでも 5 分です。親の側は、呼び出しと結果が会話の末尾に足されるだけなので、親の prefix は無傷です。
fork だけが例外です。fork は親の system prompt、ツール、モデル、会話の全部を引き継ぐので、最初のリクエストが親のキャッシュを読みます。入力の隔離を捨てる代わりに、状況を説明し直さずに済み、fork 側のツール呼び出しは親の会話に入りません。
13 体で 173 万トークンを無駄にした日(第 1 部 第 5 回)を、この表で読み直します。13 体はそれぞれ自分の system prompt と CLAUDE.md の写しを載せ、自分のキャッシュを温め、親の tool_result を 1 つも見ていないので、中央が既に読んだ資料と書いたスクリプトを各自で読み直し、書き直しました。並列実行していたので互いのキャッシュも読めません。同じ prefix のエージェントを扇状に起動して最初の 1 体のキャッシュを残りが読む仕組みは、公式には workflow の fan-out についてだけ書かれています(最大 5 秒、残りを待たせる)。Agent ツールでの並列起動については書かれていないので、私は共有されない前提で数えています。
サブエージェントの中でも圧縮は走ります。条件はメインと同じで、CLAUDE_AUTOCOMPACT_PCT_OVERRIDE も効きます。記録は ~/.claude/projects/<project>/<session-id>/subagents/agent-<id>.jsonl に、親とは別のファイルで残ります。私の手元のこのプロジェクトには、この形のファイルが 102 本ありました。第 1 部 第 5 回の「一度だけ、読む」で開く場所はここです。戻るのは最終メッセージだけで、途中の tool_use と tool_result は親には 1 つも届きません。深さは既定で 3 階層(CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH)で、上限に達したサブエージェントからは Agent ツールが外されます。機構の残り(model の解決順、外されるツール、background、frontmatter)は付録 E に置きます。
B.6 使用量の上限 —— なぜ長いセッションほど減りが速いか
第 1 部 第 5 回で私が異変に気づいたのは、使用量の上限に当たったときでした。上限は 2 種類あります。API と従量課金ではトークンの請求、定額プランでは窓ごとの使用量です。公式は Team と Enterprise について「5 時間の rolling window と週の window」と書き、You've hit your session limit / You've hit your weekly limit の表示はモデル横断なので /model で逃げられない、と書いています。
長いセッションで減りが速い理由を、公式は 1 つの節にまとめています。この章の言葉で言い直すと、全部が寿命の話です。
- 長い会話 —— 毎リクエストに全文が載る。キャッシュから読んでも、読んだ分は使用量に入る。1 行の質問でも、その日ずっと開いていた会話の全部を運ぶ
- キャッシュの miss —— TTL より長い離席の後の最初のターンは全文を計算し直す。定額なら 1 時間、usage credits に入ると 5 分、API キーなら既定 5 分
- scheduled task、別セッションからのメッセージ、goal の check-in —— 放置していても、届くたびに全文を運ぶターンが始まる
- 圧縮 —— 要約のリクエスト自体が大きい。続きが要らないなら
/clearは何も送らない - teammate —— 動いている間ずっと自分のコンテキストを運ぶ
/usage の内訳は、直近の使用量の 10% 以上を占める挙動(長い会話、キャッシュの miss)に目印を付けます。放置していても使う分もあります。--resume のための要約の背景ジョブと /usage の状態確認で、公式の目安は 1 セッション 0.04 ドル未満です。
B.7 本編との対応
| 本編 | 寿命の側から言い直すと |
|---|---|
| 第 1 部 第 2 回「メモリを読まない」 | 保存した知見は disk に行くので、次のセッションだけでなく同じセッションの次の圧縮でも読み直される。1 回の保存が効き続けるのは、3 つの寿命の外にいるから |
| 第 1 部 第 5 回「サブエージェントの出力だけは読め」 | 載るのは自分の system prompt + CLAUDE.md + task message。親の会話・tool_result・MEMORY.md は載らず、キャッシュも別で 5 分 |
| 第 1 部 第 9 回「引き継ぎを読まない」 | git diff --stat と tmp/test_last.log の件数は disk から取る数で、会話層の要約を通らない。圧縮の後でも同じ値が出る |
| 第 1 部 第 12 回「作業結果を読まない」 | 終わり際の一言は、コンテキストが上限に近い位置で打たれる。圧縮の直前か直後かで、答える AI が読んでいるものが違う(B.8) |
第 1 部 第 1 回のラッパー(tmp/test_last.log) | 「結果が見当たらない」= 圧縮の 1 段階目(古い tool_result の削除)。disk のログは、そこから戻す入口 |
| 第 2 部 序論・最終回「却下を覚えない」「同じ提案が来る」 | 会話層は次のセッションに載らない。却下を CLAUDE.md へ移す = 毎セッション読み直される部分へ移す |
B.8 本編が言っていない注意
終わり際の一言は、圧縮をまたぐと別の AI に届きます。 第 1 部 第 12 回の「不足点はないですか」は、セッションの終わりに打ちます。そこはコンテキストがいちばん埋まっている位置で、自動圧縮がその前後で走ることがあります。圧縮の後の AI が読んでいるのは、要約と直近のやり取りと読み直した 5 ファイルだけです。要約は「重要だと推測したもの」で作られるので、作業の途中で自分が省いたことは、要約にはまず載りません。本編は「完了に寄った文脈から不足は出てこない」と書きましたが、圧縮の後はその文脈すら要約に置き換わっています。守りは 2 つ。区切りで /compact を自分で走らせて、終わり際に自動圧縮が挟まる余地を減らすこと。もう 1 つは、SessionStart の compact に一致する hook で、不足点の観測に要るもの(handoff_numbers.sh の出力など)を圧縮後のコンテキストへ足し直すことです。PreCompact hook は圧縮を止められますが、止めたところで上限は消えません。
hook で毎ターン足す文脈は、圧縮で消えて、次のターンで戻ります。 私の手元では auto memory を切っていて(autoMemoryEnabled: false)、MEMORY.md を UserPromptSubmit hook で毎ターン会話層に流しています(2026-09-11 から、流しているのは全文ではなく行動ルールの節だけです。付録 C.11)。付録 A の表では project context 層にある MEMORY.md を、私は会話層に置いていることになります。違いは圧縮のときに出ます。project context 層のものは disk から読み直され、会話層のものは要約に巻き込まれます。私の場合は次に打ったターンで hook がまた流すので実害はありませんが、hook が足す文脈は、あなたが次に打つまで戻らない。自律運転(「次の作業を進めてください」の後、AI が何十ターンも続ける)の途中で圧縮が走ると、次にあなたが打つまでの間、AI は索引を持たずに動きます。
却下は 2 回死にます。 会話の中で断った提案は、圧縮で要約に巻き込まれ、セッションの終わりで消えます。第 2 部 序論が数えた「何度目か」は、セッションをまたいだ回数でしたが、長いセッションなら圧縮をまたいだ回数も足されます。却下を disk に置く理由は、セッションの独立だけではありません。
前回のログを読み直す入口は、圧縮の後に鮮度が一段落ちます。 ログに実行日時を残しておけば「コードを変えたのに前回の結果で確認する」事故は防げます。ただし圧縮の後の AI は、自分がいつ何を変えたかを要約でしか知らないので、日時を見ても「その後に変えたか」を判断する材料が薄くなります。圧縮の直後だけは、読み直しの入口が効きにくい時間帯です。
サブエージェントの 5 分は、並列の数で効きます。 13 体を並列実行すると 13 本のキャッシュを別々に書きます。1 体が 5 分以上黙ると、その 1 体のキャッシュが切れて全文を計算し直します。定額プランでもこの区分は 5 分です。長く走らせる用途なら、定義に experimental.cacheTtl: 1h を書くか、subagentPromptCacheTtl で区分ごと変えます。ただし usage credits に入っている間は 1h が無視されます。
キャッシュの共有は「同じディレクトリ・同じ git の状態」まで。 第 1 部 第 7 回の worktree の並列実行はキャッシュを共有しません。同じディレクトリで順に走らせても、間にコミットがあれば system prompt の git のブロックが変わって prefix が違います。費用を見るなら、並列実行の形と、コミットの間隔で変わります。
要約の焦点は、あなたが決められます。 CLAUDE.md に # Compact instructions の節を置けば、毎回の圧縮に効きます。本編は指示ファイルに行を足すことに慎重でしたが、この節は圧縮のリクエストにだけ効く行です。「テストの出力とコードの変更を残す」の 1 行は、テストの要約行が圧縮を生き残る確率を上げます。
transcript で圧縮を確かめる手は採りませんでした。 手元の transcript に圧縮の行を見つけられず、公式も transcript の形式を「内部のもので、版ごとに変わる」と書いています。B.9 の検証は transcript ではなく hook と /usage で見ます。
バージョン依存。 上の数値と挙動は 2026-09-05 に Claude Code 2.1.260 のドキュメントで確認したものです。スキル本文の 5,000 / 25,000 トークン、読み直す 5 ファイル、TTL の区分、Prompt cache (main) の行、resume の要約の閾値(約 1 時間、100,000 トークン)は、どれも版で変わりうる値です。
B.9 検証手順
止まるべきものが止まり、通るべきものが通る。本編と同じで、両方向を 1 度ずつ確かめます。
1. セッションの独立を、目印で確かめる。 セッション 1 で AI に「MARKER_SESSION_3e9a という語を、この会話の中でだけ覚えておいて」と伝えます。同じディレクトリで新しいセッションを開き、「MARKER_ で始まる語を知っていたら書き出して」と頼みます。期待するのは、知らないと答えることです。陽性対照として claude --continue で戻り、同じ問いに答えられることを見ます。新しいセッションで答えられたら、AI が auto memory か CLAUDE.md に書いたということで、/memory でどこに書いたかを見ます。
2. 圧縮の前後で、何が残り何が消えるかを対照する。 3 つの部分に同じ形の目印を置き、/compact の後に残る組み合わせを見ます。
{
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "echo MARKER_HOOK_5c2d" }] }],
"SessionStart": [{ "matcher": "compact", "hooks": [{ "type": "command", "command": "echo MARKER_COMPACT_7f1e" }] }],
"PreCompact": [{ "hooks": [{ "type": "command", "command": "jq -r '[.hook_event_name, .trigger, (.custom_instructions // \"\")] | @tsv' >> tmp/compact_log.tsv" }] }],
"PostCompact": [{ "hooks": [{ "type": "command", "command": "jq -r '[.hook_event_name, .trigger] | @tsv' >> tmp/compact_log.tsv" }] }]
}
}
CLAUDE.md に MARKER_CLAUDEMD_9a4b を 1 行足し、セッションを開き、AI にファイルを 2〜3 個読ませてから、MARKER_ を全部書き出させます(3 つ出るはずです。MARKER_COMPACT はまだ出ません)。次に /compact を打ち、もう一度「この会話の中に MARKER_ で始まる語があれば全部書き出して。要約に書いてあるものと、いま見えているものを分けて」と頼みます。
期待するのは 3 つです。MARKER_CLAUDEMD_9a4b が「いま見えている」側に出ること(disk から読み直された)。MARKER_COMPACT_7f1e が出ること(compact の SessionStart hook が走った)。MARKER_HOOK_5c2d は、圧縮の直後の問いの時点で UserPromptSubmit がまた走るので「いま見えている」側にも出ますが、圧縮前のぶんは要約に書かれていない限り「要約」側に無いことです。tmp/compact_log.tsv には PreCompact manual と PostCompact manual の 2 行が並びます。auto で並んでいたら、その間に自動圧縮が走っています。
3. スキル本文の上限を踏む。 本文が 5,000 トークンを超えるスキルを作り、先頭に MARKER_SKILL_TOP_1b7c、末尾に MARKER_SKILL_END_4d2e を置きます。
mkdir -p .claude/skills/long-skill
{
printf -- '---\nname: long-skill\ndescription: 圧縮の検証用。MARKER を 2 つ持つ長いスキル\n---\n'
echo 'MARKER_SKILL_TOP_1b7c'
python3 -c 'print(("この行は本文を長くするための埋め草です。" * 8 + "\n") * 400)' # ≈ 5,000 トークン超
echo 'MARKER_SKILL_END_4d2e'
} > .claude/skills/long-skill/SKILL.md
/long-skill を呼び、両方の目印が見えることを確かめてから /compact を打ち、再び目印を書き出させます。期待するのは、TOP が残り END が消えることです。両方残ったら本文が 5,000 トークンに届いていない(埋め草を増やす)か、あなたの版は上限が違います。両方消えたら、スキル本文は読み直されていません。
4. TTL の区分を数字で見る。 メインの会話がどちらの TTL で書かれたかと、強制で変わることを見ます。
claude -p "hello" --output-format json | jq '.usage.cache_creation'
# 定額プランの含まれる範囲なら ephemeral_1h_input_tokens に数が入る。API キーなら ephemeral_5m_input_tokens
FORCE_PROMPT_CACHING_5M=1 claude -p "hello" --output-format json | jq '.usage.cache_creation'
# 陰性対照: 強制すると 1h 側が 0 になる
1 回目と 2 回目で数が入る側が入れ替われば、B.4 の区分と優先順はあなたの版でも同じです。両方とも 5m 側なら、あなたの請求は 5 分の区分にいます(API キー、クラウド、または usage credits の最中)。
5. miss と expected rebuild を区別する。 /usage の Prompt cache (main) の行を見ながら、壊す操作と壊さない操作を 1 つずつ踏みます(v2.1.251 以降)。
- 数ターン普通に作業し、
/usageで miss が 0、warm であることを見る /compactを打ち、/usageを見る。expected rebuild が 1 増え、miss は増えないのが期待する結果/modelで別のモデルへ切り替えて 1 ターン打ち、/usageを見る。miss が 1 増え、v2.1.260 以降ならlikely causeにモデルの切替が出る- 陰性対照:
/permissionsでBash(rm *)のような範囲指定の deny を足して 1 ターン打つ。miss は増えない。次に裸のWebFetchを deny に足して 1 ターン打つ。miss が増える(ツール定義が system prompt 層から消えた)
6. サブエージェントに何が渡るかを、目印で確かめる。 3 つの部分に目印を置き、通常のサブエージェントと fork で見える組み合わせを対照します。
- 会話の中で「
MARKER_CONV_2c8fを覚えておいて」と伝える(会話層) - CLAUDE.md に
MARKER_CLAUDEMD_9a4bがある(project context 層。手順 2 のまま) - auto memory を有効にして、
MEMORY.mdにMARKER_MEMORY_6e3aの行を足す - AI に「general-purpose のサブエージェントを 1 体起動して、自分のコンテキストの中にある
MARKER_で始まる語を全部報告させて」と頼む - 同じことを fork(
/subtaskか、fork の指定)で頼む
期待するのは、通常のサブエージェントが MARKER_CLAUDEMD_9a4b だけを報告し、fork が 3 つとも報告することです。通常の側で MARKER_CONV か MARKER_MEMORY が出たら、あなたの版は親の会話か auto memory を渡しています。そのあと ~/.claude/projects/<project>/<session-id>/subagents/ を開き、agent-*.jsonl が 2 本増えていることを見ます。第 1 部 第 5 回の「一度だけ読む」場所です。
7. キャッシュの範囲を、ディレクトリと git の状態で踏む。 付録 A.9 の 3 を一歩進めます。
claude -p "hello" --output-format json | jq '.usage.cache_read_input_tokens' # 1 回目: 小さい
claude -p "hello" --output-format json | jq '.usage.cache_read_input_tokens' # 2 回目(5 分以内): 大きい
git commit --allow-empty -m "cache probe" -q
claude -p "hello" --output-format json | jq '.usage.cache_read_input_tokens' # 3 回目: また小さい(git の状態が変わった)
git reset --hard HEAD~1 -q
3 回目が 2 回目より明らかに小さければ、system prompt の git のブロックが prefix に入っています。小さくならなければ、あなたの版は git の状態を prefix の外に置いています。
B.10 出典(2026-09-05 確認)
- How Claude Code works —— セッションの独立、圧縮の順(古いツール出力 → 要約)、transcript の場所、resume と fork
- Explore the context window —— What survives compaction の表、スキル本文の 5,000 / 25,000、直近 5 ファイル、
/autocompact、/rewindの部分要約 - How Claude Code uses prompt caching —— 壊す操作と壊さない操作、TTL の区分と優先順、キャッシュの範囲、圧縮の要約リクエスト、サブエージェントと fork
- Manage costs effectively ——
Prompt cache (main)の行、miss の定義、長いセッションで使用量が増える理由、Compact instructions、上限の表示 - Manage sessions —— resume が復元するもの、要約からの resume(約 1 時間・100,000 トークン)、transcript の保持と形式
- Model configuration —— 自動圧縮の既定の閾値、
/autocompactの値の範囲、CLAUDE_CODE_AUTO_COMPACT_WINDOW、拡張コンテキスト - Environment variables ——
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE(下げる方向だけ・サブエージェントにも効く)、CLAUDE_CODE_DISABLE_1M_CONTEXT - Troubleshooting —— thrashing のエラー文と抜け方 4 つ
- Hooks reference ——
PreCompact/PostCompactの入力(trigger・custom_instructions)、SessionStartの matcher(startup/resume/clear/compact/fork) - How Claude remembers your project —— 圧縮後の CLAUDE.md の再読、auto memory はサブエージェントに載らない、
autoMemoryEnabled - Subagents —— 起動時に載るもの、fork、
experimental.cacheTtl、深さの上限、サブエージェント内の圧縮、transcript の場所 - Lessons from building Claude Code: Prompt caching is everything(Thariq Shihipar、2026-04-30)—— 圧縮の要約を親と同じ prefix で送る設計の理由、plan mode を tool call にした理由