本文へ移動
Claude Tips

ステータスライン

Claude Code の画面下部に出るステータスラインを、自作のシェルスクリプトで設定する方法と、スクリプトが標準入力で受け取る JSON の全フィールド、例とトラブル対処をまとめます。

ステータスラインは、Claude Code の画面下部にある、設定したシェルスクリプトを動かして内容を出すバーです。スクリプトは標準入力でセッションの JSON データを受け取り、標準出力に出したものが表示されます。コンテキストの使用量・コスト・git の状態などを、いつも見える形で出せます。

  • 複数のセッションを行き来するとき、どれかを見分けるのに使えます
  • 設定は settings.json の statusLine で行い、/statusline に望みを話すと Claude がスクリプトを作って設定します
  • ステータスラインは組み込みのフッターのバッジの上の専用の行に出て、置き換えません
  • スクリプトはローカルで動き、API のトークンを使いません
  • カスタムのステータスラインを設定すると、フッターのキーボードのヒント(esc to interrupt・? for shortcuts・hold space to speak など)の大半が出なくなります

会話に ID が出たときにフッターへクリックできるリンクのバッジを足したいだけなら、スクリプトを書かずに footerLinksRegexes を設定します(設定キー一覧)。

設定する#

/statusline コマンドで Claude Code にスクリプトを作らせるか、手でスクリプトを作って設定へ加えます。

/statusline コマンドを使う#

/statusline は、表示したいものを説明する自然言語の指示を受け付けます。Claude Code は ~/.claude/ にスクリプトファイルを作り、設定を自動で更新します。設定の途中で権限を求められたら、ファイル編集のプロンプトを承認します。

text
/statusline show model name and context percentage with a progress bar

手で設定する#

ユーザー設定(~/.claude/settings.json)かプロジェクト設定に statusLine フィールドを加えます。type は "command" にし、command はスクリプトのパスかインラインのシェルコマンドにします。

json
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2
  }
}

command はシェルで動くので、スクリプトファイルの代わりにインラインのコマンドも使えます。次の例は、jq で入力の JSON を解析し、モデル名とコンテキストの割合を出します。

json
{
  "statusLine": {
    "type": "command",
    "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
  }
}
フィールド 内容
type "command" にする(このシェルコマンドを動かす、の意味)
command スクリプトのパスか、インラインのシェルコマンド
padding 省略可。ステータスラインの内容に足す横方向の余白(文字数)。既定は 0。インターフェース組み込みの余白に加わるので、端からの絶対距離ではなく相対的なインデントを決める
refreshInterval 省略可。イベントによる更新に加えて、N 秒ごとにコマンドを再実行する。最小は 1。時計のような時間に依るデータを出すとき、またはメインのセッションが待機中にバックグラウンドのサブエージェントが git の状態を変えるときに設定する。未設定ならイベントのときだけ動く
hideVimModeIndicator 省略可。プロンプトの下の組み込みの -- INSERT -- の表示を隠す。スクリプトが vim.mode を自分で描くとき、モードが二重に出ないよう true にする

ステータスラインを無効にする#

/statusline を実行し、ステータスラインの削除かクリアを頼みます(例:/statusline delete・/statusline clear・/statusline remove it)。settings.json の statusLine フィールドを手で消してもかまいません。

手順を追って作る#

/statusline が設定してくれる内容を、現在のモデル・作業ディレクトリ・コンテキストの使用率を出すステータスラインを手で作って確かめます。例は macOS と Linux で動く Bash のスクリプトです。Windows は「Windows での設定」を見てください。

  1. 標準入力の JSON を読んで出力するスクリプトを作る。Claude Code は JSON を標準入力でスクリプトに送る。次のスクリプトは、コマンドラインの JSON パーサー jq(入れる必要があることがある)で、モデル名・ディレクトリ・コンテキストの割合を取り出し、整形した1行を出力する。~/.claude/statusline.sh に保存する

    bash
    #!/bin/bash
    # Read JSON data that Claude Code sends to stdin
    input=$(cat)
    
    # Extract fields using jq
    MODEL=$(echo "$input" | jq -r '.model.display_name')
    DIR=$(echo "$input" | jq -r '.workspace.current_dir')
    # The "// 0" provides a fallback if the field is null
    PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
    
    # Output the status line - ${DIR##*/} extracts just the folder name
    echo "[$MODEL] 📁 ${DIR##*/} | ${PCT}% context"
    
  2. 実行できるようにする

    bash
    chmod +x ~/.claude/statusline.sh
    
  3. 設定へ加える。~/.claude/settings.json に次を加えると、ステータスラインが画面の下部に出る。Claude Code は設定を自動で再読み込みし、ファイルを保存するとすぐスクリプトを動かす

    json
    {
      "statusLine": {
        "type": "command",
        "command": "~/.claude/statusline.sh"
      }
    }
    

仕組み#

Claude Code は、JSON のセッションデータを標準入力に渡してスクリプトを動かし、スクリプトが標準出力に出したものを表示します。

更新されるタイミング#

スクリプトは、セッションの開始時(再開時を含む)に1回動きます。その後は、次のときに再び動きます。

  • 新しいアシスタントのメッセージが届いたとき
  • /compact が終わったとき
  • 権限モードが変わったとき
  • Vim モードが切り替わったとき
  • statusLine 設定の command を変えたとき
  • refreshInterval を設定していれば、そのタイマーが経過したとき
  • スクリプトが最後に受け取ったデータの中のレート制限の窓が、resets_at の時刻に達したとき
  • スクリプトが最後に受け取ったデータの中の温かいプロンプトキャッシュが、expires_at の時刻に達したとき

Claude Code は更新を300msでデバウンスするので、素早い変化はまとまり、変化が止まった後にスクリプトが1回動きます。command 自体の変更はデバウンスを飛ばして、新しいコマンドをすぐ動かします。新しい更新が起きたときスクリプトがまだ動いていれば、実行中のスクリプトを取り消します。スクリプトを編集すると、変更は次に更新の引き金がスクリプトを動かし直したときに現れます。メインのセッションが待機中(コーディネーターがバックグラウンドのサブエージェントを待っているときなど)は、イベントによる引き金が静かになることがあります。時間に依る部分や外部由来の部分を待機中も新しく保つには、refreshInterval を設定して、一定のタイマーでもコマンドを動かします。

スクリプトが出力できるもの#

  • 複数行:echo や print の文ごとに別の行として表示される
  • 色:緑の \033[32m のような ANSI エスケープコードを使う(端末が対応している必要がある)
  • リンク:OSC 8 のエスケープシーケンスでテキストをクリックできるようにする(macOS は Cmd + クリック、Windows と Linux は Ctrl + クリック)。iTerm2・Kitty・WezTerm のようにハイパーリンクに対応する端末が要る

端末の大きさに合わせる#

Claude Code はスクリプトの出力を端末へ直接つながず捕まえるので、tput cols や言語側の幅の検出では、スクリプトの中から端末の大きさを読めません。代わりに環境変数 COLUMNS と LINES を読みます。Claude Code は、スクリプトを動かす前に、これらを現在の端末の大きさに設定します。

補足

ステータスラインはローカルで動き、API のトークンを消費しません。ヘルプメニューや権限プロンプトなど、特定の UI 操作の間は一時的に隠れます。

受け取るデータ#

Claude Code は、次の JSON フィールドを標準入力でスクリプトに送ります。

フィールド 説明
model.id、model.display_name 現在のモデルの識別子と表示名
cwd、workspace.current_dir 現在の作業ディレクトリ。2つは同じ値で、workspace.project_dir との整合のため workspace.current_dir を推奨
workspace.project_dir Claude Code を起動したディレクトリ。セッション中に作業ディレクトリが変わると cwd と違うことがある
workspace.added_dirs /add-dir か --add-dir で追加したディレクトリ。無ければ空の配列
workspace.git_worktree git worktree add で作ったリンク先の worktree の中にいるときの worktree 名。メインの作業ツリーでは無い。worktree.* はワークツリーセッションの間だけ現れるのに対し、これは任意の git worktree で入る
workspace.repo.host、workspace.repo.owner、workspace.repo.name origin リモートから解析したリポジトリの識別(例:"github.com"・"anthropics"・"claude-code")。git リポジトリの外、または origin が無いときは無い。サブグループに入れ子になった gitlab.com のプロジェクトでは、owner が "group/subgroup" のようにスラッシュ付きの完全な名前空間のパスになる(v2.1.260 より前は、これらのプロジェクトで workspace.repo が無かった)
cost.total_cost_usd セッションの推定コスト(USD)。modelPricing の表が有効でない限り、クライアント側で定価で計算する。実際の請求と違うことがある。/clear が新しいセッションを始めると $0 に戻る(v2.1.211 より前は、/clear の後も合計が引き継がれた)
cost.total_duration_ms セッションが動いてきた実時間の合計(ミリ秒)。再開をまたいで積み上がり、セッションが動いていない間の時間は含まない
cost.total_api_duration_ms API の応答を待った時間の合計(ミリ秒)
cost.total_lines_added、cost.total_lines_removed 変更したコードの行数
context_window.total_input_tokens、context_window.total_output_tokens 直近の API 応答から数えた、いまコンテキストの窓にあるトークン数。入力にはキャッシュの読み書きが含まれる
context_window.context_window_size コンテキストの窓の最大サイズ(トークン)。既定は 200000、拡張コンテキストのモデルは 1000000
context_window.used_percentage 事前計算された、コンテキストの窓の使用率
context_window.remaining_percentage 事前計算された、コンテキストの窓の残りの割合
context_window.current_usage 直近の API 呼び出しのトークン数。後述の「context_window のフィールド」を参照
exceeds_200k_tokens 直近の API 応答の合計トークン数(入力・キャッシュ・出力の合計)が20万を超えたか。実際のコンテキストの窓の大きさに関わらない固定のしきい値
fast_mode セッションで fast mode が有効か
effort.level 現在の推論の effort(low・medium・high・xhigh・max)。セッション途中の /effort の変更も含む、いまの値を映す。現在のモデルが effort のパラメーターに対応しないときは無い
thinking.enabled セッションで拡張思考が有効か
rate_limits.five_hour.used_percentage、rate_limits.seven_day.used_percentage 5時間または7日のレート制限の使用割合(0〜100)
rate_limits.five_hour.resets_at、rate_limits.seven_day.resets_at 5時間または7日のレート制限の窓がリセットされる Unix エポック秒
rate_limits.spend_limit.used_percentage、rate_limits.spend_limit.resets_at Claude apps gateway の背後で、支出上限の使用割合と、その期間がリセットされる時刻。下の「支出上限のフィールド」を参照。v2.1.251 以降
rate_limits.spend_limit.used_usd、rate_limits.spend_limit.limit_usd、rate_limits.spend_limit.period 支出の推定額と上限額(米ドル)、上限の期間。無いことがある。下の「支出上限のフィールド」を参照。Claude Code とゲートウェイの両方が v2.1.284 以降
prompt_cache メインの会話のプロンプトキャッシュの統計(ヒット率・ミス・キャッシュが温かいか)。全フィールドは「プロンプトキャッシュのフィールド」を参照。メインの会話の最初の API 応答までは無い。v2.1.251 以降
session_id セッションの一意の識別子
session_name セッション名。--name フラグか /rename で付けた名前があればそれ、無ければ AI が生成したセッションタイトル。my-app-3f のような既定の表示名は、このフィールドに入らない。自分の名前も AI のタイトルも無いときは無い
prompt_id いま処理中のユーザープロンプトを識別する UUID。OpenTelemetry のイベントの prompt.id 属性と一致する。最初のユーザー入力までは無い。v2.1.196 以降
transcript_path 会話のトランスクリプトファイルへのパス
version Claude Code のバージョン
output_style.name 現在の出力スタイルの名前
vim.mode Vim モードが有効なときの現在の Vim のモード(NORMAL・INSERT・VISUAL・VISUAL LINE)
agent.name --agent フラグかエージェントの設定で動かしているときのエージェント名
pr.number、pr.url 現在のブランチのオープンな pull request。フッターの PR バッジと対応する。GitLab のリモートを持つリポジトリでは、ブランチのオープンなマージリクエストから埋められ、pr.number はマージリクエストの番号になる(マージリクエストのデータは v2.1.234 以降)。git リポジトリの外、pull request やマージリクエストが見つかるまで、またはマージかクローズされた後は無い
pr.review_state オープンな PR のレビュー状態:approved・pending・changes_requested・draft。pr があっても単独で無いことがある
pr.kind pr が GitLab のマージリクエストを表すときの mr。GitHub の pull request では無いので、このフィールドより前に書いたスクリプトも動き続ける。マージリクエストでは、GitLab がマージ可能と報告すると review_state が approved、それ以外のオープンな状態は pending、ドラフトは draft になる。v2.1.234 以降
worktree.name 有効な worktree の名前。ワークツリーセッションの間だけある
worktree.path worktree ディレクトリの絶対パス
worktree.branch worktree の git ブランチ名(例:"worktree-my-feature")。フックベースの worktree では無い
worktree.original_cwd worktree に入る前に Claude がいたディレクトリ
worktree.original_branch worktree に入る前にチェックアウトしていた git ブランチ。フックベースの worktree では無い

JSON の全体像#

ステータスラインのコマンドは、次の構造の JSON を標準入力で受け取ります。

json
{
  "cwd": "/current/working/directory",
  "session_id": "abc123...",
  "session_name": "my-session",
  "prompt_id": "550e8400-e29b-41d4-a716-446655440000",
  "transcript_path": "/path/to/transcript.jsonl",
  "model": {
    "id": "claude-opus-5-5",
    "display_name": "Opus"
  },
  "workspace": {
    "current_dir": "/current/working/directory",
    "project_dir": "/original/project/directory",
    "added_dirs": [],
    "git_worktree": "feature-xyz",
    "repo": {
      "host": "github.com",
      "owner": "anthropics",
      "name": "claude-code"
    }
  },
  "version": "2.1.90",
  "output_style": {
    "name": "default"
  },
  "cost": {
    "total_cost_usd": 0.01234,
    "total_duration_ms": 45000,
    "total_api_duration_ms": 2300,
    "total_lines_added": 156,
    "total_lines_removed": 23
  },
  "context_window": {
    "total_input_tokens": 15500,
    "total_output_tokens": 1200,
    "context_window_size": 200000,
    "used_percentage": 8,
    "remaining_percentage": 92,
    "current_usage": {
      "input_tokens": 8500,
      "output_tokens": 1200,
      "cache_creation_input_tokens": 5000,
      "cache_read_input_tokens": 2000
    }
  },
  "exceeds_200k_tokens": false,
  "prompt_cache": {
    "warm": true,
    "caching_observed": true,
    "ttl": "1h",
    "expires_at": 1738429200,
    "requests": 14,
    "misses": 2,
    "expected_rebuilds": 1,
    "hit_ratio": 0.91,
    "cache_write_tokens": 352000,
    "miss_recache_tokens": 310200,
    "last_miss_at": 1738425230,
    "last_miss_cause": {
      "causes": ["tools_changed"],
      "tools_added": 2,
      "tools_removed": 0
    },
    "miss_causes": {
      "tools_changed": 2
    },
    "recache_tokens_if_cold": 45000
  },
  "fast_mode": false,
  "effort": {
    "level": "high"
  },
  "thinking": {
    "enabled": true
  },
  "rate_limits": {
    "five_hour": {
      "used_percentage": 23.5,
      "resets_at": 1738425600
    },
    "seven_day": {
      "used_percentage": 41.2,
      "resets_at": 1738857600
    },
    "spend_limit": {
      "used_percentage": 62.8,
      "resets_at": 1740787200,
      "used_usd": 314.12,
      "limit_usd": 500,
      "period": "monthly"
    }
  },
  "vim": {
    "mode": "NORMAL"
  },
  "agent": {
    "name": "security-reviewer"
  },
  "pr": {
    "number": 1234,
    "url": "https://github.com/anthropics/claude-code/pull/1234",
    "review_state": "pending"
  },
  "worktree": {
    "name": "my-feature",
    "path": "/path/to/.claude/worktrees/my-feature",
    "branch": "worktree-my-feature",
    "original_cwd": "/path/to/project",
    "original_branch": "main"
  }
}

JSON に現れないことがあるフィールドは次のとおりです。

  • session_name:--name か /rename で名前を付けたとき、または AI が生成したセッションタイトルができてから現れる。my-app-3f のような既定の表示名では入らない
  • prompt_id:最初のユーザー入力の後にだけ現れる
  • workspace.git_worktree:現在のディレクトリがリンク先の git worktree の中にあるときだけ現れる
  • workspace.repo:origin リモートが設定された git リポジトリの中だけ現れる
  • effort:現在のモデルが推論の effort のパラメーターに対応するときだけ現れる
  • vim:Vim モードが有効なときだけ現れる
  • agent:--agent フラグかエージェントの設定で動かしているときだけ現れる
  • pr:現在のブランチのオープンな PR か GitLab のマージリクエストが見つかっている間だけ現れ、マージかクローズで消える。pr.review_state と pr.kind は単独で無いことがある
  • worktree:ワークツリーセッションの間だけ現れる。あるとき、フックベースの worktree では branch と original_branch も無いことがある
  • rate_limits:claude.ai の Pro と Max の加入者、または自分に支出上限を設定する Claude apps gateway の背後でだけ、セッションの最初の API 応答の後に現れる。各窓(five_hour・seven_day・spend_limit)は単独で無いことがあり、Claude Code は resets_at の時刻が過ぎた窓を落とす。無い場合に備えて jq -r '.rate_limits.five_hour.used_percentage // empty' を使う
  • prompt_cache:メインの会話の最初の API 応答の後に現れる

null になることがあるフィールドは次のとおりです。

  • context_window.current_usage:セッションの最初の API 呼び出しの前と、/compact の後で次の API 呼び出しが埋め直すまで null
  • context_window.used_percentage、context_window.remaining_percentage:セッションの早い時期は null のことがある

スクリプトでは、無いフィールドは条件付きのアクセスで、null は代替の既定値で扱います。

支出上限のフィールド#

支出上限のある Claude apps gateway の背後では、rate_limits.spend_limit オブジェクトに、自分に適用される支出上限が入ります。セッションの最初の API 応答の後に現れ、v2.1.251 以降が必要です。スクリプトには、フィールドが別々のタイミングで届きます。

  • used_percentage と resets_at:どの応答にも付いてくるので、spend_limit があれば必ずある。used_percentage は 0〜100 で、上限を超えると 100 を超える。resets_at は上限の期間がリセットされる Unix エポック秒
  • used_usd・limit_usd・period:これまでの支出の推定額と上限額(米ドル)、上限が対象にする期間(daily・weekly・monthly のどれか)。used_usd はゲートウェイがトークン数から計算するので推定で、請求額ではない。Claude Code はこれらを別のリクエストでゲートウェイから読み、リクエストを送っている間はおよそ 5 分ごとに更新する。金額は used_percentage より最大 5 分ほど古いことがあり、2 つが一時的に食い違うことがある。Claude Code とゲートウェイの両方が v2.1.284 以降

spend_limit があっても、used_usd・limit_usd・period は無いものとして扱います。割合のほうが先に届き、CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC を設定するとそのリクエストが止まるので、ずっと無いままになります。スクリプトでは、jq -r '.rate_limits.spend_limit.used_usd // empty' のように、代替を付けて読みます。

context_window のフィールド#

context_window オブジェクトは、直近の API 応答からの、いまのコンテキストの窓を表します。

  • 合計(total_input_tokens・total_output_tokens):いまコンテキストの窓にあるトークン。total_input_tokens は input_tokens・cache_creation_input_tokens・cache_read_input_tokens の合計で、total_output_tokens は直近の応答の出力トークン。どちらも最初の API 応答の前は 0
  • 要素ごとの使用量(current_usage):同じトークン数を種類別に分けたもの。キャッシュヒットを新しい入力と分けたいときに使う

current_usage には次が入ります。

フィールド 内容
input_tokens 現在のコンテキストの入力トークン
output_tokens 生成された出力トークン
cache_creation_input_tokens キャッシュへ書かれたトークン
cache_read_input_tokens キャッシュから読まれたトークン

used_percentage は入力トークンだけから計算されます:input_tokens + cache_creation_input_tokens + cache_read_input_tokens。output_tokens は含みません。current_usage から自分でコンテキストの割合を計算するなら、used_percentage に合わせて同じ入力だけの式を使います。current_usage は、セッションの最初の API 呼び出しの前と、/compact の直後で次の API 呼び出しが埋め直すまで null です。キャッシュのフィールドの意味と課金はコンテキストとプロンプトキャッシュを参照してください。

プロンプトキャッシュのフィールド#

prompt_cache オブジェクトは、セッションのメインの会話がプロンプトキャッシュをどう使っているかをまとめます。Claude Code は API の応答のキャッシュのトークン数から計算するので、どのプロバイダーでも動きます。オブジェクトは、メインの会話の最初の API 応答の後に現れます。サブエージェントのリクエストはこの統計に数えません。v2.1.251 以降です。時刻は Unix エポック秒で、rate_limits.*.resets_at と同じ単位です。短いステータスラインは、通常これらを1つか2つ出します。warm と hit_ratio が、キャッシュの状態をいちばん直接まとめます。

フィールド 説明
warm キャッシュされた先頭部分がまだ TTL の中にあるか。直近の応答がキャッシュのトークンを報告しなかったときは、caching_observed が true でも false
caching_observed このセッションで、いずれかの応答がキャッシュのトークンを報告したか。false は、プロンプトキャッシュがオフか、プロバイダーやゲートウェイが報告しないことを意味する
ttl 現在キャッシュされている先頭部分のキャッシュの寿命:"5m" か "1h"
expires_at キャッシュされた先頭部分が TTL を出て冷える時刻(エポック秒)。直近の応答がキャッシュのトークンを報告しなかったときは null
requests このセッションで記録した、メインの会話の API リクエスト数
misses キャッシュがすでに持っていた内容を処理し直したリクエスト:キャッシュから読めたはずのトークンの5%超かつ2,000トークン以上で、キャッシュの読み取りの不足をコンパクトや古いツール結果のクリアでは説明できないもの
expected_rebuilds コンパクトや古いツール結果のクリアの後に起きた、キャッシュの作り直し
hit_ratio このセッションの全入力トークンに対するキャッシュの読み取りトークンの割合(0〜1)。分母はキャッシュの読み取り・書き込み・キャッシュなしの入力を数える。それらがすべて0の間は null
cache_write_tokens このセッションでキャッシュへ書かれた全トークン(最初のリクエストの初回の書き込みを含む)
miss_recache_tokens ミスと数えたリクエストがキャッシュへ書いたトークン
last_miss_at 最後のミスが起きた時刻(エポック秒)。セッションにミスが無い間は null
last_miss_cause 最後のミスの有力な原因として Claude Code が特定したもの。下の「最後のミスの原因」を参照。v2.1.260 以降
miss_causes このセッションで診断したミスのうち、各原因が何件あったか。last_miss_cause と同じ原因名がキー。v2.1.260 以降
recache_tokens_if_cold その時点でキャッシュが冷えていたとき、次のリクエストが再キャッシュするトークン。コンパクトや古いツール結果のクリアの直後、次のリクエストが書き換えた会話の大きさを記録するまでは null

Claude Code は、同じ統計を、/usage コマンドの「Prompt cache (main)」の行でも端末に出します。

最後のミスの原因#

last_miss_cause オブジェクトは、直近のミスの有力な原因として Claude Code が特定したものを報告します。causes の配列に、tools_changed・system_prompt_changed・ttl_expired_5m・likely_server_side など、1つ以上の原因名が入ります。セッション最初のミスまで、また直近のミスの原因を特定できなかったときは、オブジェクトが null です。v2.1.260 以降です。2つの原因は、オブジェクトに件数を加えます。

フィールド 内容
tools_added、tools_removed tools_changed とともに、リクエストへ追加された、または取り除かれたツールの数
system_char_delta system_prompt_changed とともに、システムプロンプトの長さの変化(文字数)

例#

使い方は、スクリプトを ~/.claude/statusline.sh(や .py・.js)のようなファイルに保存し、chmod +x ~/.claude/statusline.sh で実行できるようにして、そのパスを設定に加えます。Bash の例は JSON の解析に jq を使います。Python と Node.js は JSON の解析を内蔵しています。

コンテキストの使用量#

モデルとコンテキストの使用量を、進捗バーで出します。10文字のバーで、埋まったブロック(▓)が使用量です。

bash
#!/bin/bash
input=$(cat)

MODEL=$(echo "$input" | jq -r '.model.display_name')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)

BAR_WIDTH=10
FILLED=$((PCT * BAR_WIDTH / 100))
EMPTY=$((BAR_WIDTH - FILLED))
BAR=""
[ "$FILLED" -gt 0 ] && printf -v FILL "%${FILLED}s" && BAR="${FILL// /▓}"
[ "$EMPTY" -gt 0 ] && printf -v PAD "%${EMPTY}s" && BAR="${BAR}${PAD// /░}"

echo "[$MODEL] $BAR $PCT%"
python
#!/usr/bin/env python3
import json, sys

data = json.load(sys.stdin)
model = data['model']['display_name']
# "or 0" handles null values
pct = int(data.get('context_window', {}).get('used_percentage', 0) or 0)

filled = pct * 10 // 100
bar = '▓' * filled + '░' * (10 - filled)

print(f"[{model}] {bar} {pct}%")

色付きの git の状態#

git のブランチを、ステージ済みと変更済みのファイルを色分けして出します。ANSI エスケープコードで色を付けます。\033[32m が緑、\033[33m が黄、\033[0m が既定へのリセットです。

bash
#!/bin/bash
input=$(cat)

MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')

GREEN='\033[32m'
YELLOW='\033[33m'
RESET='\033[0m'

if git rev-parse --git-dir > /dev/null 2>&1; then
    BRANCH=$(git branch --show-current 2>/dev/null)
    STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
    MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')

    GIT_STATUS=""
    [ "$STAGED" -gt 0 ] && GIT_STATUS="${GREEN}+${STAGED}${RESET}"
    [ "$MODIFIED" -gt 0 ] && GIT_STATUS="${GIT_STATUS}${YELLOW}~${MODIFIED}${RESET}"

    echo -e "[$MODEL] 📁 ${DIR##*/} | 🌿 $BRANCH $GIT_STATUS"
else
    echo "[$MODEL] 📁 ${DIR##*/}"
fi

コストと経過時間#

cost.total_cost_usd は、現在のセッションの全 API 呼び出しの推定コストを積み上げます。cost.total_duration_ms はセッションが動いてきた時間の合計、cost.total_api_duration_ms は API の応答を待った時間だけです。例では、コストを通貨の形に、ミリ秒を分と秒に整えます。

複数行を出す#

echo や print の文ごとに別の行になるので、1行目に git の情報、2行目に色分けしたコンテキストのバーとコストや経過時間、のように出せます。

クリックできるリンク#

OSC 8 のエスケープシーケンスでテキストをリンクにします。Cmd(macOS)か Ctrl(Windows・Linux)を押しながらクリックすると、ブラウザで開きます。次のスクリプトは、git のリモート URL を取り、SSH 形式を HTTPS へ直し、リポジトリ名を OSC 8 で包みます。printf '%b' は、echo -e よりも、シェルを問わず確実にバックスラッシュのエスケープを解釈します。

bash
#!/bin/bash
input=$(cat)

MODEL=$(echo "$input" | jq -r '.model.display_name')

# Convert git SSH URL to HTTPS
REMOTE=$(git remote get-url origin 2>/dev/null | sed 's/git@github.com:/https:\/\/github.com\//' | sed 's/\.git$//')

if [ -n "$REMOTE" ]; then
    REPO_NAME=$(basename "$REMOTE")
    # OSC 8 format: \e]8;;URL\a then TEXT then \e]8;;\a
    printf '%b' "[$MODEL] 🔗 \e]8;;${REMOTE}\a${REPO_NAME}\e]8;;\a\n"
else
    echo "[$MODEL]"
fi

レート制限の使用量#

claude.ai のサブスクリプションのレート制限の使用量、または Claude apps gateway の支出上限に対する支出を出します。加入者の rate_limits には、ローリングの five_hour の窓と、週ごとの seven_day の窓があり、それぞれ used_percentage(0〜100)と resets_at(窓がリセットされる Unix エポック秒)を持ちます。ゲートウェイの背後では、spend_limit オブジェクトを読みます(上の「支出上限のフィールド」)。rate_limits が現れるのは、claude.ai の Pro と Max の加入者か、支出上限のある Claude apps gateway の背後で、最初の API 応答の後だけです。次のスクリプトは、無いフィールドを穏当に扱い、ゲートウェイの背後では spend: $314.12 / $500 を、金額のフィールドが無い間は spend: 63% を出します。

python
#!/usr/bin/env python3
import json, sys

data = json.load(sys.stdin)
model = data['model']['display_name']

parts = []
rate = data.get('rate_limits', {})
five_h = rate.get('five_hour', {}).get('used_percentage')
week = rate.get('seven_day', {}).get('used_percentage')

if five_h is not None:
    parts.append(f"5h: {five_h:.0f}%")
if week is not None:
    parts.append(f"7d: {week:.0f}%")

# Claude apps gateway の背後:金額が届いていれば金額、無ければ割合
spend = rate.get('spend_limit', {})
if spend.get('used_percentage') is not None:
    if spend.get('used_usd') is not None:
        parts.append(f"spend: ${spend['used_usd']} / ${spend['limit_usd']}")
    else:
        parts.append(f"spend: {spend['used_percentage']:.0f}%")

if parts:
    print(f"[{model}] | {' '.join(parts)}")
else:
    print(f"[{model}]")

重い処理をキャッシュする#

ステータスラインのスクリプトは、動いているセッションの間に頻繁に動きます。git status や git diff のようなコマンドは、大きなリポジトリでは遅くなりえます。次の方針で、git の情報を一時ファイルへキャッシュし、5秒ごとにだけ更新できます。

  • キャッシュのファイル名は、セッション内のステータスラインの呼び出しをまたいで安定し、セッションをまたいで一意である必要がある(別のリポジトリで同時に動くセッションが、互いのキャッシュした git の状態を読まないように)
  • $$・os.getpid()・process.pid のようなプロセスベースの識別子は、呼び出しのたびに変わり、キャッシュを無効にする。代わりに、入力の JSON の session_id を使う(セッションの寿命の間は安定で、セッションごとに一意)
  • git のコマンドを動かす前に、キャッシュファイルが無い、または5秒より古いかを調べる
bash
SESSION_ID=$(echo "$input" | jq -r '.session_id')
CACHE_FILE="/tmp/statusline-git-cache-$SESSION_ID"
CACHE_MAX_AGE=5  # seconds

Windows での設定#

Windows では、Claude Code は、Git Bash が入っていれば Git Bash 経由で、入っていなければ PowerShell 経由で、ステータスラインのコマンドを動かします。Git Bash は、引用符のないバックスラッシュをエスケープ文字として扱うので、C:\Users\username\script.mjs のような Windows 形式のパスは、区切りが取り除かれてスクリプトの実行側に届き、見えるエラーなしにコマンドが失敗します。command の文字列のファイルパスは、次の例のようにスラッシュで書きます。~ の短縮形も使えて、Windows のホームディレクトリに展開されます。

PowerShell のスクリプトをステータスラインにするには、powershell 経由で呼びます。Claude Code がコマンドを Git Bash 経由にしても PowerShell 経由にしても動きます。

json
{
  "statusLine": {
    "type": "command",
    "command": "powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1"
  }
}
powershell
$input_json = $input | Out-String | ConvertFrom-Json
$cwd = $input_json.cwd
$model = $input_json.model.display_name
$used = $input_json.context_window.used_percentage
$dirname = Split-Path $cwd -Leaf

if ($used) {
    Write-Host "$dirname [$model] ctx: $used%"
} else {
    Write-Host "$dirname [$model]"
}

Git Bash が入っているなら、Bash のスクリプトを直接動かすこともできます。

bash
#!/usr/bin/env bash
input=$(cat)
cwd=$(echo "$input" | grep -o '"cwd":"[^"]*"' | cut -d'"' -f4)
model=$(echo "$input" | grep -o '"display_name":"[^"]*"' | cut -d'"' -f4)
dirname="${cwd##*[/\\]}"
echo "$dirname [$model]"

サブエージェントのステータスライン#

subagentStatusLine 設定は、プロンプトの下のエージェントパネルに出る各サブエージェントの行の本体を、独自に描きます。既定の name · description · token count の行を、自分の書式に置き換えるのに使います。

json
{
  "subagentStatusLine": {
    "type": "command",
    "command": "~/.claude/subagent-statusline.sh"
  }
}

コマンドは更新のたびに1回動き、見えているすべてのサブエージェントの行を、1つの JSON オブジェクトとして標準入力で受け取ります。入力には、フックの共通の入力フィールド、使える行の幅を示す columns フィールド、tasks の配列が入ります。各タスクには id・name・type・status・description・label・startTime・cwd・tokenCount・tokenSamples と、次の表のフィールドがあります。

フィールド 内容
model そのタスクが動いている、解決済みのモデル ID。v2.1.205 以降。モデルがまだ解決していないタスクでは省かれる
contextWindowSize そのモデルのコンテキストの窓(トークン)。メインのステータスラインの context_window.context_window_size と同じ方法で計算するので、tokenCount から行ごとの割合を描ける。v2.1.205 以降。モデルがまだ解決していないタスクでは省かれる
effort そのサブエージェントに設定された推論の effort。定義の frontmatter か個々の呼び出しで指定する。値は effort のレベル(low・medium・high・xhigh・max)か、数値のトークン予算。設定された値をそのまま報告するので、モデルがそのレベルに対応しないなら、Claude Code が実際に適用する effort は違うことがある。v2.1.214 以降。サブエージェントがセッションの effort を引き継ぐときは無い

上書きしたい行ごとに、{"id": "<task id>", "content": "<row body>"} の形の JSON を1行ずつ標準出力へ書きます。content の文字列は、ANSI の色と OSC 8 のハイパーリンクを含めて、そのまま描かれます。タスクの id を省くと、その行は既定の描画のままで、空の content の文字列を出すと、その行を隠します。statusLine に適用されるのと同じ、信頼・disableAllHooks・allowManagedHooksOnly の条件がここにも適用されます。プラグインは既定の subagentStatusLine を settings.json に同梱できますが、フックと違い、プラグインの値は、管理設定の enabledPlugins でプラグインを強制的に有効にしていても、allowManagedHooksOnly の下では動きません。サブエージェントはサブエージェントを参照してください。

ヒント#

ヒント

モックの入力でテストする:echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/home/user/project"},"context_window":{"used_percentage":25},"session_id":"test-session-abc"}' | ./statusline.sh

  • 出力は短く:ステータスバーの幅は限られるので、長い出力は切り詰められるか、見づらく折り返される
  • 遅い処理はキャッシュ:スクリプトは動いているセッションの間に頻繁に動くので、git status のようなコマンドが遅延の原因になる。方法は上の「重い処理をキャッシュする」
  • ccstatusline や starship-claude のような、テーマや追加機能つきの作り込み済みの設定を提供するコミュニティのプロジェクトがある

トラブルシューティング#

ステータスラインが出ないとき:

  • スクリプトが実行できる状態か確かめる:chmod +x ~/.claude/statusline.sh
  • スクリプトが stderr でなく stdout に出力しているか確かめる
  • スクリプトを手で実行して、出力が出るか確かめる
  • Git Bash が入った Windows では、command のパスのバックスラッシュが、スクリプトが動く前にエスケープ文字として消費されている可能性が高い。パスにスラッシュを使う
  • 設定の優先順位を適用した後、管理設定の外で disableAllHooks が true なら、Claude Code は管理設定の statusLine だけを動かし、管理された statusLine が無ければステータスラインが無効になる。その設定を消すか、それを設定しているファイルで false にして、再び有効にする
  • 組織が管理設定で allowManagedHooksOnly を設定していると、カスタムのステータスラインは警告なしに消える。ステータスラインを得られるのは、その管理設定の statusLine の値からだけ。この設定が自分に当たるかは管理者に尋ねる
  • claude --debug を実行すると、ステータスラインの呼び出しのたびにスクリプトの stderr が、セッションの最初の呼び出しでは終了コードもログに出る
  • Claude に設定ファイルを読み、statusLine のコマンドを直接実行してエラーを出させる

ステータスラインが -- や空の値を出すとき:

  • フィールドは、最初の API 応答が終わる前は null のことがある
  • スクリプトで、jq の // 0 のような既定値で null を扱う
  • 何度かメッセージを送っても値が空のままなら、Claude Code を再起動する

コンテキストの割合が想定外の値のとき:

  • いちばん簡単で正確なコンテキストの状態には、used_percentage を使う
  • ステータスラインは直近の API 応答のカウントを報告し、/context はその応答以降に加わったメッセージの推定を足すので、次の応答までは /context のほうが高く読めることがある

OSC 8 のリンクがクリックできないとき:

  • 端末が OSC 8 のハイパーリンクに対応しているか確かめる(iTerm2・Kitty・WezTerm)。Terminal.app はクリックできるリンクに対応しない
  • リンクのテキストは出るがクリックできないなら、Claude Code が端末のハイパーリンクの対応を検出できていないのかもしれない。Claude Code を起動する前に、環境変数 FORCE_HYPERLINK で検出を上書きする(PowerShell では、先に現在のセッションで変数を設定する)
  • SSH と tmux のセッションは、設定によっては OSC シーケンスを取り除くことがある
  • エスケープシーケンスが \e]8;; のように文字のまま出るなら、echo -e の代わりに printf '%b' を使うと、エスケープの扱いがより確実になる
bash
FORCE_HYPERLINK=1 claude
powershell
$env:FORCE_HYPERLINK = "1"; claude

エスケープシーケンスで表示が乱れるとき:

  • 複雑なエスケープシーケンス(ANSI の色・OSC 8 のリンク)は、ほかの UI の更新と重なると、たまに出力が文字化けすることがある
  • 文字が壊れたら、スクリプトをプレーンテキストの出力に単純化してみる
  • エスケープコードを含む複数行のステータスラインは、1行のプレーンテキストより描画の問題が起きやすい

ワークスペースの信頼が要るとき:

  • statusLine はシェルコマンドを実行するので、Claude Code は、設定ファイルのフックと同じワークスペースの信頼の規則のもとで動かす。そのフォルダ、または信頼がそこへ及ぶ親ディレクトリのダイアログを受け入れれば足りる
  • それまでステータスラインは空のままで、claude --debug が Status line command skipped: workspace trust not accepted をログに出す。Claude Code を再起動して、信頼のダイアログを受け入れると有効になる

スクリプトがエラーになる・止まるとき:

  • ゼロでない終了コードで終わるスクリプトや、出力のないスクリプトは、ステータスラインを空にする
  • 遅いスクリプトは、終わるまでステータスラインの更新を止める。古い出力にならないよう、スクリプトを速く保つ
  • 遅いスクリプトが動いている間に新しい更新が起きると、実行中のスクリプトは取り消される
  • 設定する前に、モックの入力でスクリプトを単独でテストする

通知がステータスラインの行を共有するとき:フルスクリーン表示以外では、Claude Code は通知をステータスラインと同じ行に出します。フルスクリーン表示では、通知は専用の行を持ちます。

  • MCP サーバーのエラーや自動更新などのシステム通知は、行の右側に出る。コンテキストが少ないという警告のような一時的な通知も、この領域を巡る
  • verbose モードにすると、この領域にトークンカウンターが加わる
  • 狭い端末では、これらの通知がステータスラインの出力を切り詰めることがある

関連ページは、ターミナル・表示・音声入力(フルスクリーン表示)・フックのリファレンスです。

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧