Claude Media
CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFでバックグラウンド引き継ぎを止める

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFでバックグラウンド引き継ぎを止める

supervisorがバックグラウンドセッションのプロセスを再起動するとき、実行中のシェルコマンドやサブエージェントを次プロセスへ渡さず止める環境変数の挙動と設定方法。

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFとは

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFは、バックグラウンドセッションのプロセスが止まる・再起動する・更新されるときの引き継ぎを止める環境変数です。1を設定すると、実行中のシェルコマンドと動的ワークフロー、v2.1.198以降はバックグラウンドサブエージェントも、次のプロセスへ渡されずにそこで止まります。Claude Code v2.1.196以降が必要です。

既定の挙動はこの逆です。プロセスが入れ替わっても作業は次のプロセスに引き継がれ、続きが動きます。この引き継ぎはv2.1.196で入った改善で、Windowsでもバックグラウンドシェルが引き継がれるようになりました。

supervisorがプロセスを止める・再起動する場面

agent viewに載るセッションはすべてバックグラウンドセッションとして扱われます。supervisorという常駐サービスが、それぞれを個別のClaude Codeプロセスとして走らせています。プロセスの扱いは、セッションの状態で変わります。

セッションの状態supervisorの動作
作業中・許可プロンプトなどで一時停止中・アタッチ中supervisorの動作プロセスは動き続ける
完了か返信待ちで、アタッチなしのまま約1時間supervisorの動作プロセスを止めてリソースを解放する(会話はディスクに残る)
supervisor稼働中に予期せず終了したsupervisorの動作プロセスを再起動する
自動アップデート後supervisorの動作supervisor自身を新バージョンへ再起動し、アイドル中のセッションを裏で移す

Ctrl+Tでセッションをピン留めすると、アイドルでもプロセスは止められません。引き継ぎの対象になるのは、プロセスが止まる、または再起動するときです。そのとき、セッションが起動したバックグラウンドのシェルコマンド・動的ワークフロー・バックグラウンドサブエージェントは、既定では次のプロセスへ移ります。稼働中のmonitorと、サブエージェントが起動したシェルコマンドはプロセスと一緒に止まるので対象外です。セッションを削除すると、引き継がれていた作業もすべて止まります。

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF=1を設定すると、この引き継ぎ自体が行われず、プロセスの入れ替わりと一緒にすべて止まります。

設定方法

シェルでのエクスポート、またはsettings.jsonのenvキーで設定します。

export CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF=1

settings.jsonに書く場合は次のようになります。

{
  "env": {
    "CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF": "1"
  }
}

CLAUDE_DISABLE_ADOPTとの範囲の違い

似た名前のCLAUDE_DISABLE_ADOPT(v2.1.195以降)は、止める範囲が広い別の変数です。公式の環境変数一覧は、CLAUDE_DISABLE_ADOPTが両方を止めると説明しています。

くらべる

止める引き継ぎの範囲

supervisor側だけ

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF

supervisorがセッションのプロセスを停止・再起動・更新するときの引き継ぎだけを止めます。←や/backgroundで自分からバックグラウンドへ送るときは、これまでどおり引き継がれます。

両方

CLAUDE_DISABLE_ADOPT

←や/backgroundでバックグラウンドへ送るときと、supervisorによるプロセスの入れ替えのときの両方で、引き継ぎを止めます。バックグラウンドへ送る前には確認が入ります。

/background(エイリアス/bg)で送ると、実行中のバックグラウンドシェルコマンド・バックグラウンドサブエージェント・動的ワークフロー・/loopで作ったスケジュールタスク・Artifactコメントへの自動返信が、新しいプロセスで動き続けます。

Windowsでも、バックグラウンドへ送るときの引き継ぎはv2.1.195で入り、同じリリースでこの変数が使えるようになりました。

Windowsのシェルコマンドは別の変数でも切り替わる

Windowsでは、バックグラウンドのPowerShellツールのコマンドが既定でcmd.exeランチャー経由で起動します。この仕組みがあるので、セッションの次のプロセスへコマンドが引き継がれます。

CLAUDE_CODE_DISABLE_WINDOWS_SHELL_LAUNCHER(v2.1.269以降)を1にすると、PowerShellツールのコマンドをランチャーなしで直接起動します。代わりに、バックグラウンドへ送ったPowerShellコマンドは、セッションのプロセスが終わると一緒に止まります。Bashコマンドには影響しません。

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFが引き継ぎそのものを止めるのに対し、こちらはWindowsでの起動方式を切り替える変数です。対象も効果も別物です。

サブエージェントの引き継ぎには条件がある

v2.1.198以降、バックグラウンドサブエージェントも既定の引き継ぎ対象に加わりました。ただしサブエージェントは、自分が起動したものすべてと一緒に移ります。その作業全部が移れるときだけ引き継がれます。monitorを持つサブエージェントは、プロセスと一緒に止まります。

/backgroundでセッション自身を送るときにも似た制約があります。動的ワークフローがまだサブエージェントを実行中だと、Claude CodeはBackground this session?というダイアログを出し、再スタートするサブエージェントの数を示します。続行すると、実行中だったサブエージェントは最初からやり直しになり、それまでに使ったトークンも再び消費されます。Stayを選べば、先に完了を待てます。

手元のclaudeで見えるsupervisorの状態

v2.1.289のclaude daemon --helpは、supervisorの操作を次のように示します。

claude daemon --help
Service lifecycle:
  run [json-path]   Run the supervisor in the foreground (default when piped)
  status            Show daemon pid, version, uptime
  logs              Tail the daemon log (Ctrl-C to stop)
  uninstall         Remove the background service (launchctl/systemd)
  stop              Shut down the supervisor and terminate background sessions
                      --any           also stop a transient (non-service) daemon
                      --keep-workers  leave detached sessions running
 
  Service install is disabled in this version — the daemon runs on demand
  and exits when the last client disconnects.

末尾の注記が示すとおり、このバージョンのsupervisorは常駐サービスとして入らず、必要になったときに起動します。agent viewを開くかclaude --bgを実行するまでsupervisorがいない環境もあるわけです。公式のagent view解説によると、statusは到達できるかに加えて、ソケットディレクトリと稼働中のセッション数も返します。

supervisorが起動していない空の設定ディレクトリでclaude daemon statusを実行すると、出力は次のとおりです。終了コードは1でした。

not running
 
bg sessions:
  sock dir:     /tmp/cc-daemon-<uid>/<hash>
  control.sock: unreachable (connect ENOENT /tmp/cc-daemon-<uid>/<hash>/control.sock)
  bg workers:   0 in roster.json (control unreachable)
  roster.json:  absent
  daemon.log:   absent

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFFを設定した環境で、バックグラウンド処理が想定どおり止まったかを調べるときも、まずclaude daemon statusで稼働中のセッション数を見ます。実行中のclaudeとsupervisorのバージョンが食い違うと、アップデート後にsupervisorがまだ再起動していない状態として警告が出ます。

稼働中のセッションの一覧は~/.claude/daemon/roster.jsonにあり、supervisorの再起動後の再接続に使われます。CLAUDE_CONFIG_DIRを設定すると、supervisorはそのディレクトリを使う別のインスタンスとして、独自のセッションを持ちます。

各セッションの状態は~/.claude/jobs/<id>/state.jsonに保存されます。直接パースせずclaude agents --jsonで読むのが公式の推奨です。どのセッションかを特定する手順はセッションを見分ける方法にあります。

supervisorが応答しないときの再起動

アタッチやclaude logsで「バックグラウンドサービスが応答しない」と出るときは、supervisorが固まっている可能性があります。セッションを動かしたまま作り直すには、--keep-workersを付けて止めます。

claude daemon stop --any --keep-workers

次にclaude agentsかclaude --bgを実行すると新しいsupervisorが起動し、動いていたセッションへ再接続します。応答しない状態の切り分けはagent viewのbackground service応答なしの直し方にまとめています。--keep-workersを付けないと、バックグラウンドセッションも一緒に終わります。--anyは、サービスとしてではなく必要に応じて起動したsupervisorを止める、という確認の意味です。Windowsで停止要求に応答しないときは、コマンドが表示したプロセスIDをtaskkill /PID <pid>で終了させます。

止める・止めないの判断

この変数を設定する理由になるのは、次のような運用です。

  • バックグラウンドサブエージェントがデプロイや外部APIへの書き込みのような影響範囲の広い操作を実行していて、supervisorの再起動をまたいで続けたくない
  • 自動アップデートでセッションのプロセスが差し替わるとき、進行中のバックグラウンド処理をそこで区切りたい

長時間のワークフローやシェルコマンドをsupervisorの再起動・更新をまたいで完走させたいだけなら、v2.1.196以降の既定のまま使います。この変数は、その既定の引き継ぎをオプトアウトするためのものです。

止まったセッションの見え方と再開

マシンのシャットダウンなどでプロセスが止まったセッションは、agent viewではStopped(灰色)かFailed(赤)の行になります。公式のトラブルシューティングが書いているのは、マシンの再起動やシャットダウンで止まったセッションの場合です。最後に進捗があってからの経過時間で、表示と再開の手順が分かれます。

手順

シャットダウン後のセッションを再開する流れ

  1. 1

    48時間以内ならFailedと表示される

    その行にアタッチするか返信すると、止まったところから再開します。

  2. 2

    48時間を超えるとStoppedと表示される

    ended while the background service was offという案内が付きます。行でEnterを押すと、フッターに再開の確認が出ます。

  3. 3

    もう一度Enterを押すと保存済みの会話を再開する

    返信するかclaude attach <id>を実行すれば、フッターの確認なしで再開できます。

マシンをスリープさせただけではセッションは止まりません。復帰時にsupervisorが自動で再接続します。stoppedのまま放置したセッションは、transcript cleanupで保存済みの会話が消えると、行を開いても「再開する会話がない」と表示されます。引き継ぎを止める運用では、止まったセッションをいつまでに再開するか、消すかも決めておくと扱いやすくなります。

まとめ

CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF=1が止めるのは、supervisorによるプロセスの入れ替え時の引き継ぎだけです。設定したあとにプロセスが入れ替わると、バックグラウンドの作業はそこで止まり、自動では戻りません。止まった行はagent viewにStoppedかFailedで残り、アタッチするか返信すれば再開できます。止めたい作業と続けたい作業が混在するなら、止まっても再開できる状態かを先に見ておくと安全です。

この記事を共有:XはてブLinkedIn