FORCE_SESSION_PERSISTENCEで入れ子の誤判定によるセッション消失を防ぐ
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEは、入れ子セッションの誤判定でトランスクリプトが保存されない状況を解除する環境変数です。
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEは、入れ子セッションの誤判定でトランスクリプトが保存されなくなる状況を解除する環境変数です。1を設定すると誤判定を上書きできます。screenセッションやBashツール発のバックグラウンドランチャーから起動した最上位のセッションが、継承したCLAUDE_CODE_CHILD_SESSIONのせいで入れ子と誤って扱われたときに使います。tmuxではv2.1.178以降、この誤判定が自動で回避されるため変数の設定が不要になりました。
このTipsでできること
このTipsでは、CLAUDE_CODE_CHILD_SESSIONが入れ子セッションをどう判定しているかと、その判定が誤って働くケースを説明します。CLAUDE_CODE_FORCE_SESSION_PERSISTENCEを設定する具体的な手順と、バージョンによる効き方の違いもあわせて扱います。
CLAUDE_CODE_CHILD_SESSIONが入れ子セッションを見分ける仕組み
Claude Codeは、Bash・PowerShellツールやhookコマンド、tmuxセッションなどのサブプロセスを起動するとき、環境変数CLAUDECODEを1に設定します。IDE拡張機能も統合ターミナルで同じ変数をセットします。そのためこの変数だけでは、Claude Code自身が起動したプロセスかどうかまでしか判別できません。
より狭い判定に使うのがCLAUDE_CODE_CHILD_SESSIONです。この変数は、Bash・PowerShell・Monitorツール、hookコマンド、statuslineコマンドが起動したサブプロセスにだけセットされます。stdio接続のMCPサーバーのサブプロセスは対象外です。MCPサーバーのプロセスは長く動き続け、セッションが終わったあとまで残るためです。
CLAUDE_CODE_CHILD_SESSIONは、IDE拡張機能ではなくClaude Code自身がサブプロセスを起動するときにだけセットされます。この違いによって、IDEの統合ターミナルから起動した最上位のセッションと、Claude Codeがツール経由で起動した入れ子のセッションを区別できます。
入れ子と判定された対話的なclaudeのセッションは、--resume・--continue・上矢印キーの入力履歴・claude agentsの一覧から自動的に除外されます。トランスクリプトの保存そのものが止まるため、あとから会話を呼び出す手段が残りません。非対話のclaude -pセッションは、この判定に関わらずそのまま永続化されます。
継承したCLAUDE_CODE_CHILD_SESSIONが誤判定を招くケース
CLAUDE_CODE_CHILD_SESSIONは環境変数なので、子プロセスがさらに起動する孫プロセスにもそのまま引き継がれます。screenセッションの内側や、Bashツールが起動したバックグラウンドランチャーの内側で、あらためて最上位のclaudeセッションを起動すると、この継承が誤判定の原因になります。
誤判定が起きるまでの流れは、次のような連鎖になります。
- インタラクティブな
claudeセッションが、Bashツールでデプロイ用のシェルスクリプトを実行する - Claude Codeがこのサブプロセスに
CLAUDE_CODE_CHILD_SESSION=1をセットする - スクリプトの内部で、バックグラウンドランチャーやscreenセッションを介して新しい
claudeを起動する - 新しい
claudeは環境変数をそのまま引き継ぎ、独立した対話セッションのつもりで起動したにもかかわらず入れ子として扱われる
この連鎖は、間に挟まる層がscreenでもバックグラウンドランチャーでも同様に成立します。
screenセッションでも同じことが起きます。Claude CodeがBashツール経由でscreenコマンドを実行し、その画面の中で改めてclaudeを起動する場面です。screenのプロセスが継承したCLAUDE_CODE_CHILD_SESSIONの値は、そのまま新しいclaudeにも渡ります。結果として、独立したセッションのはずのトランスクリプトが保存されず、--resumeでも見つからない状態になります。
誤判定されているかを確認する
誤判定を疑う場合、新しく起動したclaudeのBashツールから継承済みの環境変数を確認します。値が1のまま残っていれば、そのセッションは入れ子として扱われています。
echo $CLAUDE_CODE_CHILD_SESSION
# 1が返れば入れ子セッション扱い。セッション終了後に--resumeの一覧を見ても出てこないもう一つの見分け方は、セッション終了後にclaude agentsの一覧を確認する方法です。独立したセッションのつもりで起動したのに一覧に現れない場合、入れ子判定が働いている可能性が高いといえます。--resumeの候補にも出てこないため、両方を照らし合わせると判断しやすくなります。
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEを設定する手順
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEを1に設定すると、継承したCLAUDE_CODE_CHILD_SESSIONを上書きします。トランスクリプトの保存とプロンプト履歴、claude agentsへの登録が強制されます。この変数専用の設定キーは無く、envブロックまたはシェルの環境変数として渡す以外の設定手段はありません。渡す先によって影響範囲が変わるため、設定はスコープの狭い方法から選びます。
もっとも影響範囲が狭いのは、ランチャースクリプトの起動コマンドにだけ変数を付ける方法です。
CLAUDE_CODE_FORCE_SESSION_PERSISTENCE=1 claudeこのコマンドで起動したときだけ反映され、ほかのclaudeの呼び出しには影響しません。
ターミナルで対話的に確認したい場合は、exportしてからclaudeを起動する方法もあります。この値はそのターミナルを閉じると消えます。
export CLAUDE_CODE_FORCE_SESSION_PERSISTENCE=1
claude常時有効にしたい場合は、設定ファイルのenvブロックに書きます。claudeを起動するたびに反映されます。
{
"env": {
"CLAUDE_CODE_FORCE_SESSION_PERSISTENCE": "1"
}
}個人のマシンだけで使うならユーザー設定に書きます。プロジェクト設定に書く場合は、そのプロジェクトで起動するすべてのclaude(本当に入れ子として動くサブセッションも含む)にトランスクリプトの保存を強制することになるので、--resumeの一覧が普段は出ないサブセッションで埋まる副作用があります。チームで共有するリポジトリに書くときは、この副作用を許容できるかを先に確認します。
バージョンによって効き方が変わる
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEが意味を持つかどうかは、Claude Codeのバージョンに強く依存します。基準になるバージョンをまとめました。
| バージョン | 挙動 |
|---|---|
| v2.1.169以前 | 挙動変数は有効。当時の入れ子判定ロジックを上書きする |
| v2.1.170・v2.1.171 | 挙動変数を設定しても効果なし。この2バージョンでは入れ子セッションの判定そのものが取り除かれていた |
| v2.1.172以降 | 挙動CLAUDE_CODE_CHILD_SESSIONによる判定が再導入され、この変数で上書きできるようになる |
| v2.1.178以降 | 挙動tmux経由のケースは自動検出され、継承したCLAUDE_CODE_CHILD_SESSIONを無視するようになった |
v2.1.170では、VS Codeの統合ターミナルや、Claude Codeの環境変数を引き継いだシェルから起動したセッションで、トランスクリプトが保存されず--resumeにも出てこない不具合が修正されました。この修正のあとに入れ子セッションの判定が仕切り直され、v2.1.172でCLAUDE_CODE_CHILD_SESSIONベースの判定に置き換わりました。screenやバックグラウンドランチャー経由の誤判定は、この再導入された判定が引き金になっています。
v2.1.178以降はtmux経由のケースが自動検出され、継承した値は無視されます。screenやBashツール発のバックグラウンドランチャーは自動検出の対象外なので、引き続きこの変数で上書きします。
似た名前の環境変数との役割の違い
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEは、セッションを保存するかどうかの判定を元に戻すための変数です。似た効果を持つ他の変数と役割を混同しやすいため、早見表にまとめました。
| 変数 | 効果 | 向き |
|---|---|---|
CLAUDECODE | 効果サブプロセスかどうかだけを示す | 向き判定用(IDE拡張機能もセット) |
CLAUDE_CODE_CHILD_SESSION | 効果ツール経由のサブプロセスかを示し、入れ子セッションの判定に使われる | 向き判定用(Claude Code自身のみセット) |
CLAUDE_CODE_FORCE_SESSION_PERSISTENCE | 効果入れ子判定を上書きし、保存を強制する | 向き上書き用 |
CLAUDE_CODE_SKIP_PROMPT_HISTORY | 効果モードを問わず履歴とトランスクリプトの書き込みを止める | 向き保存を止める側 |
CLAUDE_CODE_SKIP_PROMPT_HISTORYは保存を止める側の変数で、CLAUDE_CODE_FORCE_SESSION_PERSISTENCEとは向きが逆です。両方を同時に設定した場合にどちらが優先されるかは、公式ドキュメントに明記されていません。用途が対立する組み合わせなので、通常はどちらか一方だけを使う場面です。--no-session-persistenceフラグとの関係はClaude Codeの--session-idと--no-session-persistenceの使い方にまとめています。あちらはprint mode限定のフラグという違いがあります。
よくあるつまずき
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEを設定しても保存されない場合、まずバージョンを確認します。v2.1.170とv2.1.171では、上書き対象になる入れ子判定そのものが存在しません。そのため変数を設定しても挙動は変わりません。
tmux経由で入れ子と誤判定されるケースは、v2.1.178以降であれば自動で解消されています。この変数を設定してもtmuxの表示に変化がない場合は、原因がtmux以外(screenやカスタムのバックグラウンドランチャー)にある可能性を確認します。
非対話のclaude -pセッションに対してこの変数を設定しても意味がありません。claude -pはCLAUDE_CODE_CHILD_SESSIONの値に関わらず、トランスクリプトが保存される仕様だからです。対象になるのは対話的なclaudeセッションに限られます。
シェルでexportした直後は反映されないこともあります。Claude Codeは起動時にシェルの環境変数を読み込むため、変更を反映するにはclaudeを新しく起動し直す必要があります。すでに動いているセッションの中でexportしても、そのセッション自体には効きません。
トランスクリプトが実際にどこに保存されているかを確認したい場合は、Claude Codeのセッションエクスポートとトランスクリプトの保存場所にまとめています。保存先のディレクトリ構造や、エクスポートしたトランスクリプトの読み方まで確認できます。セッションが誤って前回の会話を引き継ぐ別種の不具合については、Claude Codeのworktreeが再利用されるバグも参考になります。
まとめ
CLAUDE_CODE_FORCE_SESSION_PERSISTENCE=1は、screenセッションやBashツール発のバックグラウンドランチャーから継承したCLAUDE_CODE_CHILD_SESSIONによって、最上位のセッションが入れ子と誤判定されたときの回避策です。v2.1.172以降で意味を持ち、v2.1.170・v2.1.171では効果がありません。tmux経由の誤判定はv2.1.178で自動対応済みなので、この変数が必要になるのはtmux以外の起動経路に限られます。設定してもトランスクリプトが保存されない場合は、まずバージョンと起動経路を確認します。