ステータスライン
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/ にスクリプトファイルを作り、設定を自動で更新します。設定の途中で権限を求められたら、ファイル編集のプロンプトを承認します。
/statusline show model name and context percentage with a progress bar
手で設定する#
ユーザー設定(~/.claude/settings.json)かプロジェクト設定に statusLine フィールドを加えます。type は "command" にし、command はスクリプトのパスかインラインのシェルコマンドにします。
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}
command はシェルで動くので、スクリプトファイルの代わりにインラインのコマンドも使えます。次の例は、jq で入力の 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 での設定」を見てください。
-
標準入力の 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" -
実行できるようにする
bashchmod +x ~/.claude/statusline.sh -
設定へ加える。
~/.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 を標準入力で受け取ります。
{
"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 呼び出しが埋め直すまでnullcontext_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文字のバーで、埋まったブロック(▓)が使用量です。
#!/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%"
#!/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 が既定へのリセットです。
#!/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 よりも、シェルを問わず確実にバックスラッシュのエスケープを解釈します。
#!/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% を出します。
#!/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秒より古いかを調べる
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 経由にしても動きます。
{
"statusLine": {
"type": "command",
"command": "powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1"
}
}
$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 のスクリプトを直接動かすこともできます。
#!/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 の行を、自分の書式に置き換えるのに使います。
{
"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'を使うと、エスケープの扱いがより確実になる
FORCE_HYPERLINK=1 claude
$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日時点の内容をもとに、日本語でまとめています。