statuslineでworktreeセッションを表示する — worktree.*フィールドの条件
Claude Codeのstatuslineが運ぶworktree.name/path/branch等5フィールドの出現条件と、workspace.git_worktreeとの違い・hookで作ったworktreeでの欠落を解説します。
Claude Codeのstatuslineは、セッション自体がworktree内で動いているときだけ、stdinのJSONにworktreeオブジェクトを追加します。フィールドはname・path・branch・original_cwd・original_branchの5つです。どのworktreeで何をしているセッションかを、statuslineに常時表示できます。似た名前のworkspace.git_worktreeとは出現条件がまったく違うため、混同すると意図と違う場面でフィールドが空になります。
並列に開いた複数セッションを見分ける手段には/colorや/renameもあります。ただしこれらはセッションに名前や色を明示的に付ける機能です。worktree単位で動いているかどうかまで含めて自動的に判別したい場合は、statuslineのworktree.*が名前を付ける手間なく直接使えます。
worktree.*とworkspace.git_worktreeの違い
stdinのJSONには、worktreeに関するフィールドが2系統あります。名前が似ているため、実装時に混同しやすいところです。
2系統のworktreeフィールド
worktree.*
セッション自体がworktreeセッションのときだけ現れます。対象はclaude --worktreeでの起動、EnterWorktreeでの移動、worktreeセッションのresumeの3経路です。名前・パス・元のブランチまで、5フィールドを運びます。
workspace.git_worktree
カレントディレクトリがgit worktree addで作ったリンク済みworktreeの中にあるとき、値が入ります。--worktreeを使わず手動でcdしただけでも出ますが、メインの作業ツリーでは出ません。値はworktree名の文字列1つだけです。
worktree.nameが空でもworkspace.git_worktreeだけは値を持っていることがあるので、statuslineスクリプトでは両方を見ておくと取りこぼしが減ります。worktree全般の使い方はClaude Code Worktree実践ガイドで扱っています。
worktree.*が運ぶ5つのフィールド
| フィールド | 内容 |
|---|---|
worktree.name | 内容アクティブなworktreeの名前 |
worktree.path | 内容worktreeディレクトリの絶対パス |
worktree.branch | 内容worktreeに紐づくgitブランチ名(例: worktree-my-feature)。hookで作ったworktreeでは欠落 |
worktree.original_cwd | 内容worktreeに入る前にClaudeがいたディレクトリ |
worktree.original_branch | 内容worktreeに入る前にチェックアウトされていたgitブランチ。hookで作ったworktreeでは欠落 |
original_cwdとoriginal_branchは、worktreeに入る前のディレクトリとブランチをそれぞれ保持します。複数のworktreeを行き来する運用では、この2つを表示に組み込むと、いまのセッションがどこから移動してきたのかがstatuslineだけで分かります。JSON全体では次の形で渡ります。
"worktree": {
"name": "my-feature",
"path": "/path/to/.claude/worktrees/my-feature",
"branch": "worktree-my-feature",
"original_cwd": "/path/to/project",
"original_branch": "main"
}worktreeセッションとして扱われる3つの経路
worktreeオブジェクトが現れるのは、セッション自体がworktreeセッションであるときです。
worktreeセッションになる3つの経路
- 1
claude --worktree <name> で起動する
-wでも同じです。既定では.claude/worktrees/<name>/に、worktree-<name>という名前の新しいブランチで作られます。 - 2
EnterWorktree ツールで移動する
セッション中にClaudeが別のworktreeへ入り直します。
- 3
worktreeセッションをresumeする
worktreeの中で終わったセッションを再開すると、Claude Codeがセッションをそのworktreeへ戻します。
Sub-agentのfrontmatterにisolation: worktreeを指定すると、そのSub-agentは自分専用のworktreeで動きます。Sub-agent向けのstatuslineにはsubagentStatusLineという別枠があり、渡されるJSONはtasks配列を持つ構造です。worktree.*はセッション全体がworktreeセッションの間だけ現れるフィールドなので、Sub-agentの隔離とは別の話として扱います。
セッションを--fork-sessionでforkした場合、フォークされたセッションは元のセッションを起動したディレクトリで始まり、元セッションが使っていたworktreeはそのまま残ります。
hookで作ったworktreeで欠けるフィールド
WorktreeCreatehookでSVNやPerforceなど非gitのVCSにworktree作成を差し替えている場合、worktree.branchとworktree.original_branchは欠落します。statuslineのリファレンスは、この2つが欠けうるのは「hook-based worktrees」、つまりhookで作ったworktreeだと書いています。たとえばSVNのワーキングコピーには、gitのブランチがありません。欠落対象として挙がっているのはこの2つだけで、worktree.name・worktree.path・worktree.original_cwdは欠落の対象に含まれていません。
非gitのVCSでworktree作成・削除を差し替える手順は、WorktreeCreate/WorktreeRemove hookでworktreeの作成・削除を差し替えるにあります。statusline側で分岐を書くときは、ブランチ系フィールドの欠落を前提にします。
セッション中にworktreeの状態が変わる場面
worktreeオブジェクトはセッション開始時の1回きりの値ではなく、セッションがworktreeセッションであり続けている間だけ出続けます。
ClaudeがEnterWorktreeツールで別のworktreeへ移動する場合があります。移動先がリポジトリの.claude/worktrees/ディレクトリの外にあるときは、Claude Codeが先にユーザーの承認を求めます。移動すると、セッションの作業ディレクトリ・書き込み権限・CLAUDE.mdや設定がその場所に移るためです。
EnterWorktreeの権限ルールを許可済みにしていても、「今後確認しない」を選んでいても、この確認はスキップされません。bypassPermissionsモードのときだけ確認なしで移動します。v2.1.206より前は、既存のworktreeパスなら確認なしで入れました。
worktreeオブジェクトはセッションがworktreeセッションである間だけ現れるため、ExitWorktreeツールでworktreeを抜けて通常のセッションに戻れば、statuslineは普段の表示になります。
resumeでworktreeに戻れないとき
resumeしたセッションが元のworktreeへ戻れないときは、隔離なしで続きます。Claude Codeはresume時に、worktreeがまだ隔離されたチェックアウトのままかを検証します。この検証の結果、画面に出るメッセージは3種類あります。
resume時の3つのメッセージ
Your worktree <path> no longer exists
worktreeのディレクトリが消えています。セッションは起動したディレクトリで続き、Claude Codeがworktreeへの紐付けを消去します。対処は不要です。
Could not verify your worktree <path> this time
検証ができなかった場合です。通常は一時的な理由で、紐付けは残ったまま、隔離なしで続きます。もう一度resumeすると再試行されます。
Did not re-enter your worktree <path>
Claude Codeがそのworktreeの紐付けを安全でないと判断し、拒否しました。紐付けは消去され、隔離なしで続きます。メッセージには個別の拒否理由が付きます。
「さっきまで出ていたworktree名が急に消えた」と感じたら、まずworktreeディレクトリが削除されていないかを確かめ、次にこの3種のメッセージのどれが出ていたかを見ます。
いつstatuslineスクリプトが再実行されるか
worktree.*の値を含め、statuslineスクリプトはセッション開始時(resume時を含む)に一度実行されます。その後は次のイベントをきっかけに再実行され、表示が更新されます。
- 新しいアシスタントメッセージが届いたとき
/compactが完了したとき- パーミッションモードが変わったとき
- vimモードが切り替わったとき
statusLineのcommandを書き換えたときrefreshIntervalのタイマーが満了したとき(設定している場合)- 直近に受け取ったデータのレート制限ウィンドウが
resets_atに達したとき、またはプロンプトキャッシュがexpires_atに達したとき
一方、コーディネーターがバックグラウンドのSub-agentを待っているだけでメインセッションがアイドル状態のときは、イベント駆動の更新が静かになります。バックグラウンド側のworktree作業をリアルタイムに近い形で追いたい場合は、refreshIntervalを設定してタイマーでも再実行させます。最小値は1秒です。
Claude Codeはこれらの更新を300ミリ秒でデバウンスするため、短時間に複数の変化が重なっても、スクリプトの実行は1回にまとまります。実行中に次の更新トリガーが来た場合は、その実行を打ち切って新しい入力で再実行します。command自体を書き換えたときだけはデバウンスを飛ばし、新しいコマンドがすぐ走ります。
statuslineスクリプトへの組み込み例
statuslineの基本設定はClaude Code statuslineの設定と表示項目の選び方にまとめています。ここではworktree.*とworkspace.git_worktreeの分岐だけを書きます。
#!/bin/bash
input=$(cat)
if [ -n "$(echo "$input" | jq -r '.worktree.name // empty')" ]; then
NAME=$(echo "$input" | jq -r '.worktree.name')
BRANCH=$(echo "$input" | jq -r '.worktree.branch // "branchなし"')
echo "🌳 ${NAME} (${BRANCH})"
elif [ -n "$(echo "$input" | jq -r '.workspace.git_worktree // empty')" ]; then
echo "🌿 $(echo "$input" | jq -r '.workspace.git_worktree')"
else
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
echo "📁 ${DIR##*/}"
fiworktree.nameはworktreeセッションでないときに存在しないので、// emptyで空文字へフォールバックさせてから-nで判定します。worktree.branchに// "branchなし"を付けているのは、hookで作ったworktreeでも行が崩れないようにするためです。
優先順位はworktree.name、workspace.git_worktree、通常のディレクトリ名の順です。名前だけならjq -r '.worktree.name // .workspace.git_worktree // empty'と//を連結して1行で書けます。ただしこの形だと、workspace.git_worktreeだけが入る場面でもworktree.branchを参照することになります。ブランチ欄は存在しない値のフォールバック表示になってしまいます。上のように分岐を分けると、表示を使い分けられます。
並列で複数のworktreeを行き来する運用では、worktree.original_branchを足して「どこから来たセッションか」まで1行に収めることもできます。gitのworktreeとhookで作ったworktreeを色分けしたいときは、worktree.branchが存在するかどうかを判定に使えます。ブランチがあれば緑、なければ黄色のANSIエスケープを添えるといった具合です。
実際にworktreeを作らずに分岐を検証する
この分岐が正しく動くかは、worktreeセッションを起動しなくても、モックのJSONをスクリプトに流せば確かめられます。
echo '{"worktree":{"name":"my-feature","branch":"worktree-my-feature","original_cwd":"/path/to/project","original_branch":"main"},"workspace":{"current_dir":"/path/to/.claude/worktrees/my-feature"}}' | ~/.claude/statusline.shv2.1.289のClaude Codeを入れた環境で、上のスクリプトに4種類のJSONを流した結果は次のとおりでした。claude --helpの一覧には-w, --worktree [name]が「Create a new git worktree for this session」として載っています。
| 流したJSON | 出力 |
|---|---|
worktreeあり(branchあり) | 出力🌳 my-feature (worktree-my-feature) |
worktreeあり(branchなし。hook作成を想定) | 出力🌳 svn-wc (branchなし) |
workspace.git_worktreeのみ | 出力🌿 wt2 |
| どちらもなし | 出力📁 main |
名前を//で連結し、ブランチを// "no-branch"で引く形に「workspace.git_worktreeのみ」のJSONを流すと、出力はwt2 (no-branch)になりました。worktree.branchは手動でcdしただけのworktreeには付かないためです。worktreeオブジェクトごと外したJSONでは、worktreeセッションでないときの通常表示に戻ります。
まとめ
worktree.*は、複数のworktreeで並列にセッションを走らせているときに効くフィールド群です。分岐はworktree.name、workspace.git_worktree、ディレクトリ名の順に書き、branch系の欄は常に欠ける前提で// "no-branch"のようなフォールバックを付けておくと、どのセッションを触っているかをstatuslineだけで判別できます。