---
title: "付録 B コンテキストの寿命 —— 圧縮・キャッシュ・サブエージェント"
author: garplab
publisher: TypingTube
license: All rights reserved
license_scope: 記事の全体（序論・最終回は CC BY 4.0 の対象外）。引用は法の範囲で自由
canonical: https://typing-tube.net/articles/furoku-b-context-lifetime
series: "付録"
language: ja
---


先に結論です。**Claude Code のコンテキストには、長さの違う寿命が 3 つ重なっています。** 1 ターンの寿命（ツールの出力は次のリクエストに載り、圧縮で最初に消える）、セッションの寿命（会話は次のセッションに 1 行も持ち越されない）、そしてキャッシュの寿命（同じ prefix を 5 分か 1 時間、API 側が覚えている）。本編が「AI は却下を覚えない」と言い、「結果が流れたら再実行しかない」と言い、「サブエージェントには何も渡っていない」と言ったことは、この 3 つの寿命のどれかの話です。

付録 A は 1 ターンのリクエストに何が載るかを解剖しました。この章は、載ったものがいつ消えるかを追います。圧縮は何をどの順で消し、何を読み直すか。キャッシュはいつ切れ、何が切るか。サブエージェントは親の何を引き継ぎ、何を引き継がないか。読み終えたら、本編の各回が「なぜファイルに置いたか」を、寿命の側から言い直せるはずです。

## B.1 3 つの寿命

```mermaid
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.

```mermaid
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` の後に残る組み合わせを見ます。

```json
{
  "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` を置きます。

```bash
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 で書かれたかと、強制で変わることを見ます。

```bash
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 以降）。

1. 数ターン普通に作業し、`/usage` で miss が 0、warm であることを見る
2. `/compact` を打ち、`/usage` を見る。**expected rebuild が 1 増え、miss は増えない**のが期待する結果
3. `/model` で別のモデルへ切り替えて 1 ターン打ち、`/usage` を見る。**miss が 1 増え**、v2.1.260 以降なら `likely cause` にモデルの切替が出る
4. 陰性対照: `/permissions` で `Bash(rm *)` のような範囲指定の deny を足して 1 ターン打つ。miss は増えない。次に裸の `WebFetch` を deny に足して 1 ターン打つ。miss が増える（ツール定義が system prompt 層から消えた）

**6. サブエージェントに何が渡るかを、目印で確かめる。** 3 つの部分に目印を置き、通常のサブエージェントと fork で見える組み合わせを対照します。

1. 会話の中で「`MARKER_CONV_2c8f` を覚えておいて」と伝える（会話層）
2. CLAUDE.md に `MARKER_CLAUDEMD_9a4b` がある（project context 層。手順 2 のまま）
3. auto memory を有効にして、`MEMORY.md` に `MARKER_MEMORY_6e3a` の行を足す
4. AI に「general-purpose のサブエージェントを 1 体起動して、**自分のコンテキストの中にある `MARKER_` で始まる語を全部**報告させて」と頼む
5. 同じことを 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 を一歩進めます。

```bash
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](https://code.claude.com/docs/en/how-claude-code-works) —— セッションの独立、圧縮の順（古いツール出力 → 要約）、transcript の場所、resume と fork
- [Explore the context window](https://code.claude.com/docs/en/context-window) —— What survives compaction の表、スキル本文の 5,000 / 25,000、直近 5 ファイル、`/autocompact`、`/rewind` の部分要約
- [How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching) —— 壊す操作と壊さない操作、TTL の区分と優先順、キャッシュの範囲、圧縮の要約リクエスト、サブエージェントと fork
- [Manage costs effectively](https://code.claude.com/docs/en/costs) —— `Prompt cache (main)` の行、miss の定義、長いセッションで使用量が増える理由、Compact instructions、上限の表示
- [Manage sessions](https://code.claude.com/docs/en/sessions) —— resume が復元するもの、要約からの resume（約 1 時間・100,000 トークン）、transcript の保持と形式
- [Model configuration](https://code.claude.com/docs/en/model-config) —— 自動圧縮の既定の閾値、`/autocompact` の値の範囲、`CLAUDE_CODE_AUTO_COMPACT_WINDOW`、拡張コンテキスト
- [Environment variables](https://code.claude.com/docs/en/env-vars) —— `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`（下げる方向だけ・サブエージェントにも効く）、`CLAUDE_CODE_DISABLE_1M_CONTEXT`
- [Troubleshooting](https://code.claude.com/docs/en/troubleshooting) —— thrashing のエラー文と抜け方 4 つ
- [Hooks reference](https://code.claude.com/docs/en/hooks) —— `PreCompact` / `PostCompact` の入力（`trigger`・`custom_instructions`）、`SessionStart` の matcher（`startup` / `resume` / `clear` / `compact` / `fork`）
- [How Claude remembers your project](https://code.claude.com/docs/en/memory) —— 圧縮後の CLAUDE.md の再読、auto memory はサブエージェントに載らない、`autoMemoryEnabled`
- [Subagents](https://code.claude.com/docs/en/sub-agents) —— 起動時に載るもの、fork、`experimental.cacheTtl`、深さの上限、サブエージェント内の圧縮、transcript の場所
- [Lessons from building Claude Code: Prompt caching is everything](https://claude.com/blog/lessons-from-building-claude-code-prompt-caching-is-everything)（Thariq Shihipar、2026-04-30）—— 圧縮の要約を親と同じ prefix で送る設計の理由、plan mode を tool call にした理由
