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が起動したサブプロセスなのか、IDE拡張機能の統合ターミナルなのかを区別できません。CLAUDECODEはstdio接続のMCPサーバーのサブプロセスにもセットされます。
より狭い判定に使うのが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セッションは、この判定に関わらずそのまま永続化されます。
手元のBashツールで実物を見る
Claude CodeのBashツールの中で2つの変数を表示すると、どちらも1が入っています。次の出力はv2.1.289で確認したものです。
echo "CHILD_SESSION=$CLAUDE_CODE_CHILD_SESSION CLAUDECODE=$CLAUDECODE FORCE=[$CLAUDE_CODE_FORCE_SESSION_PERSISTENCE]"
# CHILD_SESSION=1 CLAUDECODE=1 FORCE=[]Bashツールの中で何かを起動すると、起動先は最初からCLAUDE_CODE_CHILD_SESSION=1を持った状態になります。一方CLAUDE_CODE_FORCE_SESSION_PERSISTENCEは自動では入りません。次の節で扱う誤判定は、CLAUDE_CODE_CHILD_SESSIONの値が孫プロセスへ素通しされることで起きます。
継承したCLAUDE_CODE_CHILD_SESSIONが誤判定を招くケース
CLAUDE_CODE_CHILD_SESSIONは環境変数なので、子プロセスがさらに起動する孫プロセスにもそのまま引き継がれます。screenセッションの内側や、Bashツールが起動したバックグラウンドランチャーの内側であらためて最上位のclaudeセッションを起動すると、この継承が誤判定の原因になります。誤判定は次の順で起きます。
入れ子と誤判定されるまで
- 1
Bashツールでスクリプトを実行する
インタラクティブな
claudeセッションが、デプロイ用のシェルスクリプトなどをBashツールで実行します。 - 2
サブプロセスに印が付く
Claude Codeはこのサブプロセスに
CLAUDE_CODE_CHILD_SESSION=1をセットします。 - 3
新しいclaudeを起動する
スクリプトの内部で、バックグラウンドランチャーやscreenセッションを介して新しい
claudeを起動します。 - 4
入れ子として扱われる
新しい
claudeは環境変数をそのまま引き継ぎます。独立した対話セッションのつもりで起動しても、トランスクリプトは保存されず--resumeにも出てきません。
誤判定されているかを確認する
v2.1.217では、環境変数の継承でセッションの保存が切れているときに警告が出るようになりました。誤判定を疑うときは、まずこの警告の有無を見ます。トランスクリプトの書き込みが失敗したとき(ディスクが一杯のときなど)にも、同じく警告が出ます。
警告が出ない場合は、誤判定を疑うセッションを終了したあと、claude --resumeの一覧やclaude agentsにそのセッションが出てくるかを見ます。出てこなければ、入れ子判定が働いている疑いがあります。Bashツールの中では変数の値が常に1なので、値そのものは判断材料になりません。
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ブロックに書く方法もあります。効かないときは、上の起動コマンドへの前置きに戻します。
{
"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設定しても効果なし
上書き対象の入れ子判定そのものが取り除かれていました。
- v2.1.172以降CHILD_SESSIONによる除外が対象
CLAUDE_CODE_CHILD_SESSIONはv2.1.172以降が必要な変数で、この変数で除外を上書きします。 - v2.1.178以降tmuxは自動で回避
tmux経由のケースを自動検出し、継承したマーカーを無視します。
v2.1.170(2026年6月9日)では、トランスクリプトが保存されず--resumeにも出てこない不具合が修正されました。対象は、VS Codeの統合ターミナルや、Claude Codeの環境変数を引き継いだシェルから起動したセッションです。screenやバックグラウンドランチャー経由の誤判定は、v2.1.172以降に残る入れ子判定の側で起きます。
screenやBashツール発のバックグラウンドランチャーはv2.1.178の自動検出の対象外なので、引き続きこの変数で上書きします。
似た名前の環境変数との役割の違い
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とは向きが逆で、1にすると--resume・--continue・上矢印の履歴にセッションが出なくなります。両方を設定した場合の優先順位は、どちらの説明にも書かれていません。
--no-session-persistenceフラグも保存を止める側です。v2.1.289のclaude --helpには次の説明が出ます。
claude --help
# --no-session-persistence Disable session persistence - sessions
# will not be saved to disk and cannot be
# resumed (only works with --print)(only works with --print)のとおり、対象はclaude -pだけです。詳しい使い方はClaude Codeの--session-idと--no-session-persistenceの使い方にあります。
よくあるつまずき
CLAUDE_CODE_FORCE_SESSION_PERSISTENCEを設定しても保存されない場合、まず上のTimelineでバージョンを照らします。
tmuxの内側で起動した場合は、v2.1.178以降なら変数なしで保存されます。tmuxの内側で保存されないときは、まずv2.1.178以降かを確認します。v2.1.178以降なのに保存されないなら、原因がtmux以外(screenやカスタムのバックグラウンドランチャー)にある可能性を疑います。
非対話のclaude -pセッションに対しては、この変数に意味がありません。claude -pはCLAUDE_CODE_CHILD_SESSIONの値に関わらず保存されます。対象は対話的なclaudeセッションに限られます。
シェルでexportした直後に、すでに動いているセッションの中で試しても効果は出ません。変数は起動するclaudeに渡す値なので、claudeを新しく起動し直します。
保存先を確かめたいときは、Claude Codeのセッションエクスポートとトランスクリプトの保存場所が保存先のディレクトリ構造とエクスポートしたトランスクリプトの読み方を扱っています。セッションが前回の会話を引き継いでしまう別種の不具合は、Claude Codeのworktreeが再利用されるバグも参考になります。
まとめ
最初に起動コマンドへCLAUDE_CODE_FORCE_SESSION_PERSISTENCE=1を前置きして試し、効いたら必要な範囲だけenvに昇格させます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。