Claude Media
statuslineでworktreeセッションを表示する — worktree.*フィールドの条件

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全体では次の形で渡ります。

stdin JSON(worktree部分の抜粋)
"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. 1

    claude --worktree <name> で起動する

    -wでも同じです。既定では.claude/worktrees/<name>/に、worktree-<name>という名前の新しいブランチで作られます。

  2. 2

    EnterWorktree ツールで移動する

    セッション中にClaudeが別のworktreeへ入り直します。

  3. 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の分岐だけを書きます。

~/.claude/statusline.sh
#!/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##*/}"
fi

worktree.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.sh

v2.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だけで判別できます。

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