Claude Media
Claude Code forkコマンドでセッションをバックグラウンドに複製する

Claude Code forkコマンドでセッションをバックグラウンドに複製する

/forkは会話をバックグラウンドセッションに複製し、元のセッションはそのまま続けられます。/subtask・/branchとの違い、worktree分離、削除時に何が消えるかを実機のhelpと突き合わせて扱います。

Claude Code forkコマンドは何をするコマンドか

/forkは今の会話をまるごとコピーし、新しいバックグラウンドセッションとして走らせるコマンドです。元のセッションは手元に残り、作業を止めずに続けられます。コピーには会話履歴に加えて、モデル・権限モード・effortレベルが引き継がれます。セッション中に追加した作業ディレクトリと、許可確認で「今後は確認しない(don't ask again)」を選んだ許可も渡ります。

引数にプロンプトを渡すと、コピーはそのタスクをすぐに始めます。プロンプトなしで実行したときは、agent view上で最初の指示を待ちます。エラーではないので、claude agentsでその行を選んでSpaceを押すか、claude attach <id>で指示を送れば動き出します。

/fork これまでの作業内容でドラフトのプルリクエストを作成して

実行すると、コピーの状態・agent view上の行の名前・claude attach用のセッションIDを示す確認メッセージが1行で出ます。行の名前をクリックすると、今のセッションはバックグラウンドへ退き、agent viewがコピー側のセッションを開きます。

コピーと元の会話は、その後は互いに独立です。コピーが何をしても元の会話には入ってきません。例外は、セッション間メッセージ(cross-session messaging)が有効な環境で、どちらかのClaudeが相手へ明示的にメッセージを送る場合だけです。結果を元の会話へ戻したいときは、次節の/subtaskの領分になります。

/fork・/subtask・/branchのどれを打つか

似た3つのコマンドは、「コピーがどこで動き、結果がどこへ戻るか」で選び分けます。

3択

会話を分けるコマンドの使い分け

  • /fork

    コピーを独立したバックグラウンドセッションとして送り出し、自分は元のセッションに残ります。ドラフトPRの作成や別方針の試作のように、結果を会話へ戻す必要がない仕事向きです。

  • /subtask

    会話を引き継ぐバックグラウンドのサブエージェントを走らせ、終わったら結果が今の会話に返ってきます。調べ物やテストケースの下書きなど、結果を使って今の作業を続けたい仕事向きです。

  • /branch

    自分自身が分岐した会話へ切り替わります。元の会話は保存され、/resumeで戻れます。分かれた先で自分が手を動かしたいときの選択肢です。

大きめの実装が一段落したところで/fork open a draft pull request with the work so farと打てば、コピーがPR作成という後始末を引き受け、自分は次のタスクへ移れます。設計で迷ったときは、同じ会話から/forkを2回実行して2通りの実装を別々のセッションに任せ、結果を見比べてから片方を選ぶ使い方もあります。どちらも、コピー側が背景説明なしに経緯を把握している点が効きます。

3つの違いはClaude Code subtaskコマンドの記事で詳しく比べています。バックグラウンドで走る複数のセッションを一覧管理する仕組みはagent viewの記事にまとめてあります。

コピーはどこで、どのcheckoutを触るのか

コピーがコード変更を始める前に、Claude Codeは「自分専用のgit worktreeを作ってから編集する」よう指示します。元のセッションが今編集しているcheckoutとコピーの作業がぶつからないための仕組みで、worktreeの基本はそちらの記事にあります。この指示はClaude Code v2.1.221以降です。それより前はコピーに分離の指示がなく、元のセッションが使っているworktreeやcheckoutをそのまま編集してしまうことがありました。

コピーがどこから始まるかは、元のセッションの置かれ方で変わります。確認メッセージの末尾の注記で見分けられます。

注記

確認メッセージの末尾で分かる4つの状況

  • 注記なし

    通常のケースです。コピーは他のバックグラウンドセッションと同じく、編集の前に.claude/worktrees/以下の自分のworktreeへ移ります。

  • runs in the origin tree(1)

    元のセッションが起動後にlinked worktreeへ入っていた場合です。コピーは移動前の場所から始まり、そこで自分用のworktreeを作ります。worktreeがブランチをチェックアウトしていて、コピーの仕事がその続きなら、元のブランチを起点にした新しいブランチを作るよう指示されます。

  • runs in the origin tree(2)

    最初からlinked worktreeの中で起動していた場合です。コピーはリポジトリのメイン作業ツリーから始まり、自分用のworktreeを作ります。ブランチに関する指示は付きません。

  • edits this checkout

    bare repositoryの構成にあるworktreeで起動した場合と、worktree分離を切った環境でlinked worktreeの外から起動した場合です。コピーは今開いているファイルをその場で編集します。

「元のブランチを起点に新ブランチ」は上の2枚目だけの挙動で、どのコピーでも自動で起きるわけではありません。git管理外のディレクトリでは、フック(WorktreeCreate)が無い限りコピーはその場で編集します。フックが設定されていれば、フックで作ったworktreeから出たコピーだけが分離の指示を受けます。

worktree分離そのものを切りたいリポジトリでは、プロジェクトの.claude/settings.jsonに次を足します。バックグラウンドセッションが作業コピーを直接編集するようになるので、edits this checkoutの注記が出る状況が増えます。

{
  "worktree": {
    "bgIsolation": "none"
  }
}

分離が効いたコピーが作業を終えるときの振る舞いも決まっています。worktreeに入ってコードを変えたセッションは、消えても作業が残るように、確認なしでコミットし、リモートがあればブランチをpushします。必要ならドラフトPRも開きます。mainやmasterへのpush・force push・マージは行いません。依頼文やCLAUDE.md、メモリに「コミットやpushは自分でやる」と書いてあれば、そちらが優先されてgitには触れません。分離していないcheckoutを編集しているセッションは、コミットやブランチ切り替えの前に今までどおり確認を求めます。

forkできないケースと、環境で挙動が変わるケース

置換したシステムプロンプトや--toolsの許可リストのように、コピー側が引き継げない起動フラグで始めたセッションは、/forkできません。不完全なコピーは作らず、その旨が表示されます。agent viewから送り出したセッションは普通にforkでき、コピーは元と同じagent定義と追加指示で起動します。

agent viewを無効にした環境では、/forkの意味そのものが変わります。disableAgentView設定をtrueにするか、環境変数CLAUDE_CODE_DISABLE_AGENT_VIEWを設定すると、/forkは今も会話を引き継ぐforkサブエージェントを起動します。このとき/subtaskは使えません。同じ名前のコマンドが、環境によって別の動作を指す点に注意してください。

また、v2.1.232で対話セッションの既定がオンになった「fork mode」は、ClaudeがAgentツールで自律的にforkサブエージェントを呼ぶかどうかの設定です。ユーザーが打つ/forkとは別物で、環境変数CLAUDE_CODE_FORK_SUBAGENTの1でオン、0でオフに上書きできます。詳細はClaude Code v2.1.232のリリースノートで扱っています。

/forkコマンドの変遷

/forkという名前のコマンドは、指す挙動がバージョンごとに変わってきました。

バージョン/forkの挙動
〜v2.1.160/forkの挙動会話を分岐して自分がそちらへ切り替わる(v2.1.77で/branchに改名され、/forkは別名として残る)
v2.1.161〜v2.1.211/forkの挙動会話履歴を引き継ぐバックグラウンドのサブエージェントを起動する(今の/subtask相当)
v2.1.212/forkの挙動会話全体を新しいバックグラウンドセッションへ複製する、今の挙動に切り替わる。旧挙動は/subtaskへ分離
v2.1.216/forkの挙動確認メッセージが1行になり、コピーの名前をクリックして直接切り替えられる
v2.1.221/forkの挙動コピーに独自worktreeでの分離が指示される
v2.1.246/forkの挙動コピー元が「コピーしたばかりで新しいプロンプトをまだ記録していないセッション」でも会話が引き継がれる

v2.1.246の行は、実際に踏みやすい不具合の修正です。それ以前は、/forkしたコピーにattachして、新しいプロンプトを送る前にもう一度/forkすると、確認メッセージは普通に出るのに、できたコピーの会話が空でした。←や/backgroundで背景に移したセッションを再度attachした場合や、claude --resume <id> --fork-sessionで始めたセッションも同じ条件です。同じ状態のセッションを←や/backgroundで背景へ送った場合も、会話が失われていました。古いバージョンを使い続けている環境では、孫コピーを作る前に一言プロンプトを送っておけば、この条件には当たりません。

シェルからコピーを操作する

コピーには短いIDが付き、~/.claude/jobs/<id>/というディレクトリ名としても確認できます。agent viewを開かなくても、このIDでシェルから操作できます。v2.1.286のclaude --helpと各サブコマンドの--helpで、次の説明を確認しました。

$ claude attach --help
Usage: claude attach <id>
 
  Open the background session in this terminal. ← returns to agent view, Ctrl+Z drops back to your shell. The session keeps running either way.
 
$ claude stop --help
Usage: claude stop <id>
 
  Stop a background session. Its conversation is kept; resume it later with `claude attach <id>`.
 
$ claude respawn --help
Usage: claude respawn <id>|--all
 
  Restart a background session (or all of them) so it picks up the current Claude binary.
手順

コピーの寿命に沿った操作

  1. 1

    起動したら状態を見る

    claude agentsで一覧を開くか、スクリプトからならclaude agents --jsonを使います。待機中のコピーにはspace to send it a promptと表示されます。

  2. 2

    様子を見る、割り込む

    接続せずに直近の出力だけ眺めるならclaude logs <id>、画面ごと操作するならclaude attach <id>です。peek画面から返信を送ると、作業中のセッションではメッセージキューに入り、今の応答は中断されません。

  3. 3

    止める、載せ替える

    claude stop <id>(claude killの名前でも呼べます)で止めます。Claude Codeを更新したあと、古いバイナリのまま動いているコピーはclaude respawn <id>で載せ替え、全部まとめてならclaude respawn --allです。止めたセッションも会話は残るので、後からclaude attach <id>で目覚めさせられます。

  4. 4

    片付ける

    claude rm <id>で一覧から外します。worktreeがどうなるかは次節のとおり、状況で変わります。

スクリプトから状態を見るときは、claude agents --jsonの出力が公式に案内された経路で、~/.claude/jobs/<id>/state.jsonを直接読む方法は勧められていません。stateにはworking / blocked / done / failed / stoppedのいずれかが入ります。ここで落とし穴になるのが--allで、--helpにも「--jsonと組み合わせたときだけ完了済みを含める」と書かれています。既定の--jsonが出すのは、生きているセッションと、まだworkingかblockedのバックグラウンドセッションだけです。完了したコピーを拾うにはclaude agents --json --allと書く必要があり、doneを待つループを--allなしで書くと、完了した行が一覧から消えて永遠に見つかりません。

同じclaude agentsには絞り込みの--cwd <path>もあります。指定したパス以下で始まったセッションだけを出すので、複数のリポジトリでコピーを走らせていても、いま見たいプロジェクトの分だけを拾えます。

コマンドラインから同じ複製を作る経路もあります。claude --bg --resume <session-id>は、そのセッションを同じIDのままバックグラウンドで続けます(v2.1.257以降)。すでに動いているセッションに対して実行すると、新しいIDでコピーを作り、note:の行でそう伝えます。--continueや、名前・ファイルパスでの--resumeと組み合わせたときは、常にコピーになります。--fork-sessionを--resumeや--continueと組み合わせると、元のIDを使い回さず新しいセッションIDで始まります。ターミナルを離れた先から複製したいときや、スクリプトに組み込むときに、/forkの代わりになります。

バックグラウンドセッションの中で動くシェルコマンドには、環境変数CLAUDE_JOB_DIRが渡されます。指す先は~/.claude/jobs/<id>で、$CLAUDE_JOB_DIR/tmpに一時ファイルを書けば、並行して動く他のコピーと名前がぶつかりません。このtmpへのWriteとEditは権限の確認が出ず、セッションを削除すると一緒に消えます。

blockedは、質問・権限やsandboxの確認・ログイン切れのように、あなたにしか解けない待ちを指します。プロンプトなしで始めた/forkの最初の指示待ちもblockedです。自動化では、blockedのコピーを見つけたらwaitingForの値(permission prompt・input neededなど)で次の動きを分けられます。

claude rmで何が消えて、何が残るか

コピーを消すと、そのコピーのために作られたworktreeがどうなるかは、消し方で違います。ここは誤解しやすい点です。

消し方コミットしていない変更worktree
agent viewでCtrl+Xを2回コミットしていない変更変更ごと削除されるworktree削除される
claude rm <id>コミットしていない変更変更が残っていれば削除を拒否し、行もworktreeも残すworktree変更がなければ削除される

agent viewの側は変更を巻き込んで消すので、残したい作業は先にコミットしておく必要があります。claude rmは変更があれば止まる安全側の動作です。どちらの場合も、会話のトランスクリプトはローカルに残り、claude --resumeから辿れます。

もう一つの防御は、pushされていないコミットです。worktreeにリモートにもメインのブランチにも無いコミットがあると、削除は拒否され、ブランチ名と未pushの件数が表示されます。選択肢は2つで、pushかマージをしてからもう一度消すか、破棄を承知でもう一度消すかです。claude rmでは、拒否メッセージに出た値を渡す形になります。実機のclaude rm --helpは次のとおりです(長いoption説明は途中まで抜粋しています)。

$ claude rm --help
Usage: claude rm <id> [--discard-unpushed <commit>@<worktree-id>] [--force-remove-worktree <worktree-id>]
 
  Delete a background session and its worktree. Unlike `stop`, works on already-exited sessions.
  --discard-unpushed <commit>@<worktree-id>  also discard the worktree's unpushed commits (and any uncommitted changes) while it is still the same worktree at that commit — pass the value a previous 'claude rm <id>' reported
  --force-remove-worktree <worktree-id>      delete the worktree directory even though the WorktreeRemove hook or git couldn't remove it (...; the branch is kept) — pass the value a previous 'claude rm <id>' reported

--discard-unpushedは拒否メッセージが印字したコミットとworktree IDの組を渡すと、未pushのコミットと変更ごとブランチを破棄します。その間にコミットが増えていれば、新しい状態を示して止まります。--force-remove-worktreeはgitやフックがworktreeを消せなかったときの最後の手段で、ディレクトリだけを消してブランチは残します。それぞれv2.1.260以降、v2.1.268以降が対象です。

他のセッションが使用中またはロックしているworktreeは、どの方法でも消えません。自分でgit worktree addして、その中でセッションを始めた場合も、worktreeはそのまま残ります。

利用枠と、マシンの電源の話

バックグラウンドセッションは対話セッションと同じようにサブスクリプションの利用枠を消費します。/forkで10個のコピーを並べれば、1個のときの約10倍の速さで枠が減ります。並行数を増やす価値は、枠の減り方と引き換えです。

コピーはローカルのマシンで動きます。スリープでは止まらず、復帰するとsupervisor(バックグラウンドセッションを預かる常駐プロセス)が再接続します。シャットダウンでは止まり、復帰後の見え方は、最後に作業が進んでからの時間で変わります。入力待ちだったセッションは、戻ったあともNeeds inputの下に残ります。それ以外の実行中だったセッションは次の表のとおりです。

最後に進んでからの経過行の状態再開のしかた
48時間以内行の状態failed再開のしかたattachするか返信すると、続きから再開する
48時間超行の状態ended while the background service was off付きのstopped再開のしかたEnterを押し、確認メッセージが出たらもう一度押す

完了して次の入力を待っているコピーは、約1時間そのままにするとsupervisorがプロセスだけを止めて資源を空けます。会話はディスクに残り、attachや返信で続きから動きます。プロセスを動かし続けたいコピーは、Ctrl+Tでピン留めできます。agent viewを開いている間は、バックグラウンドのコピーが入力待ち・完了・失敗に変わるたびに、設定済みの通知経路へ知らせが届きます。

まとめ

コピーを増やすほど、後片付けで効く知識が増えます。残したい作業はコピーを消す前にコミットかpushまで済ませておくと、Ctrl+Xで変更ごと消える事故を避けられます。claude rmは変更があれば止まりますが、未pushのコミットを破棄するかどうかの判断は、--discard-unpushedに渡す前に自分で下す必要があります。完了待ちのスクリプトは、claude agents --json --allで書いておけば完了した行を取りこぼしません。

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