
Claude Codeのstatuslineをカスタマイズしてセッションのステータス状況を見える化する
はじめに
データ事業本部の荒木です。
Claude Code を業務で使っていると、「いまどのモデルで動いているのか」「コンテキストはあとどれくらい残っているのか」「5 時間枠のレート制限はいつリセットされるのか」を一目で確認したくなることはありませんか。デフォルトの statusline は最小限の情報しか出ないので、毎回 /status を叩いたりブラウザで使用状況を確認したりしていました。
そこで statusline.sh を書いて、必要な情報を 2 行にまとめて常時表示するようにしたので、初めて触る方にも分かるように作成手順をまとめます。
最終的にこんな表示になります。
my-project (main*↑2)
Opus 4.7 [1M] | ctx ▓▓▓▓░░░░░░ 58% (107k) | 1h57m | 5h 17%(rst 2h12m) / 7d 10%(rst 3d0h) | $3.59 | thinking · effort:high · style:concise
- 1 行目 に「いまどこで作業しているか」(プロジェクト名 + git ブランチ + dirty 印 + ahead/behind)
- 2 行目 に「セッションの状況」(モデル + コンテキスト残量バー + 経過時間 + レート制限 + 累計コスト + 思考モード)
環境
- WSL2 (今回は WSL2 + Ubuntu 22.04 で確認)
- Claude Code CLI (v2.1 以降を想定。statusline 機能は 2025 年以降のバージョン)
- Bash 5.x
jq(statusline に渡される JSON のパースに使用、未インストールならapt install jqなどで導入)
本題
statusline とは
公式ドキュメント (ステータスラインをカスタマイズする) によると、statusline は Claude Code の画面下部に常時表示されるカスタマイズ可能なバーで、設定したシェルスクリプトを実行して、その標準出力を表示する仕組みです。
ステータスラインは Claude Code の下部にあるカスタマイズ可能なバーで、設定したシェルスクリプトを実行します。stdin 経由で JSON セッションデータを受け取り、スクリプトが出力したものを表示し、コンテキスト使用状況、コスト、git ステータス、またはその他の追跡したい情報を一目で確認できる永続的なビューを提供します。
つまり、stdin に流れてくる JSON を任意の言語のスクリプトで整形して stdout に出すだけで、そのまま画面下部に出力される、という仕組みです。Bash / Python / Node.js / PowerShell など、JSON を読めるものなら何でも使えます。
スクリプトに渡される JSON を確認する
公式ドキュメントの 利用可能なデータ によると、JSON には以下のような項目が含まれます (抜粋)。本記事で実際に使うものに ★ を付けました。
| フィールド | 内容 |
|---|---|
model.display_name ★ |
モデル表示名 (例: Claude Opus 4.7 (1M context)) |
workspace.current_dir / project_dir ★ |
作業ディレクトリ / プロジェクトディレクトリ |
context_window.used_percentage / remaining_percentage ★ |
コンテキストウィンドウの使用率 / 残量 |
context_window.current_usage.* ★ |
入力 / 出力 / キャッシュ各トークン数 |
rate_limits.five_hour.used_percentage ★ |
5 時間枠の使用率 |
rate_limits.five_hour.resets_at ★ |
リセット Unix エポック秒 |
rate_limits.seven_day.* ★ |
7 日枠 (同様) |
cost.total_cost_usd ★ |
セッション累計コスト (USD) |
cost.total_duration_ms ★ |
セッション経過時間 |
effort.level ★ |
推論努力レベル (low / medium / high / xhigh / max) |
thinking.enabled ★ |
拡張思考が有効か |
output_style.name ★ |
現在の出力スタイル |
session_id |
セッション ID (キャッシュキーに有用) |
session_name |
--name や /rename で付けた名前 |
worktree.* |
--worktree セッション中の worktree 情報 |
rate_limits は Claude.ai サブスクライバー (Pro/Max) のみ、effort は対応モデルのみといった具合に、存在しないケースがあるフィールドが多いので、スクリプト側で // empty (jq) や null 判定でフォールバックを書いておくのが安全です。
statusline.sh の作成 (パーツ別解説)
スクリプトは ~/.claude/scripts/statusline.sh に配置します。中身をパーツごとに分けて見ていきます。
Claude Code はこのスクリプトを実行するとき、セッションの情報 (モデル名・コンテキスト残量・コストなど) を JSON 形式でスクリプトに流し込んできます。まずはその JSON をまるごと変数 input に読み込んでおき、以降の各パーツでは input から欲しい値を jq で取り出していきます。
input=$(cat)
1. 共通部品: ANSI カラーとフォーマット関数
statusline は背景色を持続させたいので、行内 reset では BG を再適用するパターンを使います。色は「残量系 (高いほど緑)」と「使用率系 (低いほど緑)」の 2 種類を用意します。
C_BG=$'\033[48;5;236m' # 背景: 暗いグレー
C_END=$'\033[0m' # 行末: 完全 reset
C_RESET="${C_END}${C_BG}" # 行内 reset: 全 reset 後に BG 再適用
C_GREEN=$'\033[32m'
C_YELLOW=$'\033[33m'
C_RED=$'\033[31m'
C_CYAN=$'\033[36m'
C_DIM=$'\033[2m'
# 残量に対する色 (高い方が緑)
color_for_remaining() {
local pct=$1
if [ "$pct" -ge 50 ]; then echo "$C_GREEN"
elif [ "$pct" -ge 25 ]; then echo "$C_YELLOW"
else echo "$C_RED"; fi
}
# 使用率に対する色 (低い方が緑)
color_for_usage() {
local pct=$1
if [ "$pct" -lt 50 ]; then echo "$C_GREEN"
elif [ "$pct" -lt 75 ]; then echo "$C_YELLOW"
else echo "$C_RED"; fi
}
色閾値はコンテキスト残量が 50% / 25% で切り替え、使用率系は 50% / 75% で切り替え。視覚的に「赤 = 危険」で一貫させると、横目で見ても判断できます。
整形ヘルパも 2 つ用意しておきます。トークン数を 1.2k / 1.2M 形式に丸めるのと、秒数を 1h2m / 3d0h などに整形するものです。
fmt_tokens() {
awk -v n="$1" 'BEGIN{
if (n >= 1000000) printf "%.1fM", n/1000000;
else if (n >= 1000) printf "%dk", n/1000;
else printf "%d", n;
}'
}
fmt_duration() {
local sec=$1
if [ "$sec" -ge 86400 ]; then
local d=$((sec / 86400)); local h=$(( (sec % 86400) / 3600 ))
printf "%dd%dh" "$d" "$h"
elif [ "$sec" -ge 3600 ]; then
local h=$((sec / 3600)); local m=$(( (sec % 3600) / 60 ))
printf "%dh%dm" "$h" "$m"
else
printf "%dm" $((sec / 60))
fi
}
make_bar() {
local pct=$1 width=${2:-10}
local filled=$((pct * width / 100))
[ "$filled" -gt "$width" ] && filled="$width"
local empty=$((width - filled))
local out=""
for ((i=0; i<filled; i++)); do out="${out}▓"; done
for ((i=0; i<empty; i++)); do out="${out}░"; done
printf '%s' "$out"
}
make_bar が ▓▓▓▓░░░░░░ のような 10 文字のプログレスバーを返す関数です。
2. モデル名
Claude Opus 4.7 (1M context) のような長い表記を Opus 4.7 [1M] に縮めます。
model=$(echo "$input" | jq -r '.model.display_name // .model.id // "unknown"')
model=$(echo "$model" \
| sed -E 's/^Claude //' \
| sed -E 's/ \(([0-9]+M) context\)/ [\1]/')
3. プロジェクト + git ブランチ
workspace.project_dir から basename を取り、git リポジトリなら branch + dirty フラグ (*) + ahead/behind (↑↓) を付けます。GIT_OPTIONAL_LOCKS=0 を付けると git の lock 取得を回避でき、頻繁に呼ばれる statusline スクリプトで安心です。
project_dir=$(echo "$input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // ""')
cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // ""')
proj=$(basename "$project_dir")
git_info=""
if [ -n "$cwd" ] && GIT_OPTIONAL_LOCKS=0 git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
branch=$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null \
|| GIT_OPTIONAL_LOCKS=0 git -C "$cwd" rev-parse --short HEAD 2>/dev/null)
dirty=""
[ -n "$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" status --porcelain 2>/dev/null | head -1)" ] && dirty="*"
ab=""
upstream_count=$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" rev-list --left-right --count @{upstream}...HEAD 2>/dev/null)
if [ -n "$upstream_count" ]; then
behind=$(echo "$upstream_count" | awk '{print $1}')
ahead=$(echo "$upstream_count" | awk '{print $2}')
[ "$ahead" != "0" ] && ab="${ab}↑${ahead}"
[ "$behind" != "0" ] && ab="${ab}↓${behind}"
fi
git_info="${branch}${dirty}${ab}"
fi
main*↑2 のように 1 文字単位で詰め込めるので、視認性を保ちながら情報量を増やせます。
4. コンテキスト残量 (プログレスバー + 残量% + 実トークン数)
context_window.used_percentage でプログレスバーを描画し、remaining_percentage で残量%を表示します。残量に応じて色を変え、current_usage の各トークン数を合算した実トークン数を dim で添えます。
ctx_part=""
remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
if [ -n "$used_pct" ] && [ "$used_pct" != "null" ]; then
used_pct_int=$(printf "%.0f" "$used_pct")
if [ -n "$remaining" ] && [ "$remaining" != "null" ]; then
rem_pct_int=$(printf "%.0f" "$remaining")
else
rem_pct_int=$((100 - used_pct_int))
fi
color=$(color_for_remaining "$rem_pct_int")
bar=$(make_bar "$used_pct_int" 10)
ctx_part="ctx ${color}${bar}${C_RESET} ${color}${rem_pct_int}%${C_RESET}"
used=$(echo "$input" | jq -r '
(.context_window.current_usage // {})
| (.input_tokens // 0)
+ (.output_tokens // 0)
+ (.cache_creation_input_tokens // 0)
+ (.cache_read_input_tokens // 0)
')
if [ -n "$used" ] && [ "$used" != "null" ] && [ "$used" -gt 0 ]; then
used_fmt=$(fmt_tokens "$used")
ctx_part="${ctx_part} ${C_DIM}(${used_fmt})${C_RESET}"
fi
fi
ctx ▓▓▓▓░░░░░░ 58% (107k) のような形になり、「残量パーセント」「視覚的バー」「実トークン数」の 3 つを同時に表現できます。1M context モデルだとパーセントだけでは絶対量が分かりにくいので、トークン数を添えるのがポイントです。
5. レート制限 (使用率 + リセットまでの残り時間)
5 時間枠と 7 日枠の使用率を / 区切りで並べ、resets_at (Unix エポック秒) から「あと何時間でリセットされるか」を計算して dim 表示します。now = date +%s との差分を fmt_duration に通すだけです。
now=$(date +%s)
fmt_until_reset() {
local reset_at=$1
[ -z "$reset_at" ] || [ "$reset_at" = "null" ] && return
local diff=$((reset_at - now))
[ "$diff" -le 0 ] && { echo "now"; return; }
fmt_duration "$diff"
}
rate_part=""
five_h=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_h_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
seven_d=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
seven_d_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
rate_segs=()
if [ -n "$five_h" ] && [ "$five_h" != "null" ]; then
pct=$(printf "%.0f" "$five_h")
color=$(color_for_usage "$pct")
rest=$(fmt_until_reset "$five_h_reset")
seg="5h ${color}${pct}%${C_RESET}"
[ -n "$rest" ] && seg="${seg}${C_DIM}(rst ${rest})${C_RESET}"
rate_segs+=("$seg")
fi
# 7d も同様 (省略)
5h と 7d の区切りは | ではなく / にしています。| だと別カテゴリに見えるので、「同じレート制限グループ」だと示すために細い区切りを使うのがおすすめです。
リセット時刻が分かると、「あと 2 時間で 5 時間枠がリセットされるから、いまの重い作業は終わらせて休憩したほうがいい」のような判断ができるようになります。
6. 経過時間とコスト
duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // empty')
if [ -n "$duration_ms" ] && [ "$duration_ms" != "null" ]; then
total_sec=$((duration_ms / 1000))
session_elapsed=$(fmt_duration "$total_sec")
fi
cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty')
if [ -n "$cost_usd" ] && [ "$cost_usd" != "null" ]; then
cost_part=$(printf "\$%.2f" "$cost_usd")
fi
7. 思考モード (thinking / effort / output_style)
「ハイモード系」を有効にしたまま忘れて長時間動かしてしまうとコスト要因になります。thinking.enabled / effort.level / output_style.name を dim で 2 行目末尾に表示しておくと、視野には入りつつ邪魔にならないので便利です。デフォルトの出力スタイルだけは出さないようにしています。
mode_segs=()
thinking=$(echo "$input" | jq -r '.thinking.enabled // empty')
[ "$thinking" = "true" ] && mode_segs+=("thinking")
effort=$(echo "$input" | jq -r '.effort.level // empty')
[ -n "$effort" ] && [ "$effort" != "null" ] && mode_segs+=("effort:${effort}")
ostyle=$(echo "$input" | jq -r '.output_style.name // empty')
[ -n "$ostyle" ] && [ "$ostyle" != "null" ] && [ "$ostyle" != "default" ] && mode_segs+=("style:${ostyle}")
8. 組み立てて 2 行で出す
最後に各パーツを 2 行に分けて連結します。1 行目はプロジェクト + git ブランチ、2 行目はモデルから先のセッション状況です。空のパーツは詰めて、HOME 直下にいるときはプロジェクト名を出さないなどの細工も入れます。
# 1 行目: プロジェクト (ブランチ)
line1_parts=()
if [ "$project_dir" != "$HOME" ] && [ -n "$proj" ]; then
if [ -n "$git_info" ]; then
line1_parts+=("${C_CYAN}${proj}${C_RESET} (${git_info})")
else
line1_parts+=("${C_CYAN}${proj}${C_RESET}")
fi
elif [ -n "$git_info" ]; then
line1_parts+=("(${git_info})")
fi
# 2 行目: モデル | ctx | 時間 | レート | コスト | モード
line2_parts=("$model")
[ -n "$ctx_part" ] && line2_parts+=("$ctx_part")
[ -n "$session_elapsed" ] && line2_parts+=("$session_elapsed")
[ -n "$rate_part" ] && line2_parts+=("$rate_part")
[ -n "$cost_part" ] && line2_parts+=("$cost_part")
[ -n "$mode_part" ] && line2_parts+=("$mode_part")
join_with_sep() {
local out=""
for p in "$@"; do
if [ -z "$out" ]; then out="$p"; else out="${out}${C_DIM} | ${C_RESET}${p}"; fi
done
printf '%s' "$out"
}
line1=$(join_with_sep "${line1_parts[@]}")
line2=$(join_with_sep "${line2_parts[@]}")
[ -n "$line1" ] && printf '%b\n' "${C_BG}${line1}${C_END}"
printf '%b\n' "${C_BG}${line2}${C_END}"
スクリプトを保存したら、実行可能フラグを立てるのを忘れずに。
chmod +x ~/.claude/scripts/statusline.sh
settings.json への登録
~/.claude/settings.json の statusLine セクションに、作成したスクリプトのパスを書きます。
{
"statusLine": {
"type": "command",
"command": "bash ~/.claude/scripts/statusline.sh",
"padding": 1
}
}
オプションの padding は左右の余白で、デフォルト 0 です。refreshInterval を秒数指定すると、イベント駆動更新に加えて N 秒ごとにスクリプトを再実行できますが、本記事の構成ではイベント駆動だけで十分です。
動作確認
設定後のカスタムstatuslineが出力されるとこんな感じです。

コンテキスト残量が 25% を切ると赤色になるため、視覚的に「そろそろ /compact するか別セッションに切り替えるか」を判断しやすくなります。レート使用率は 75% を超えると赤色になるので、長時間作業時の上限到達を予測しやすくなりました。
ただ個人的には、1Mを使っている場合50%から60%になる前にはセッションを切り替えるなりclearするなりをした方がいいと思っています。
50%切ってくると、AIの回答の精度が極端に悪くなってくるなーという感じがするので。
他に表示できそうなもの (拡張アイデア)
公式ドキュメントに記載されている JSON フィールドのうち、本記事で取り入れなかったものでも、ユースケースによっては便利なものがあります。気になる方は組み込んでみてください。
- PR バッジ + クリック可能リンク:
pr.number/pr.url/pr.review_stateを OSC 8 ハイパーリンクで包んで、現在のブランチのオープン PR とレビュー状態 (approved / pending / changes_requested / draft) を表示できます。ただし GitHub.com 上の PR にしか対応していない (内部的にghCLI 経由で取得しているため) ので、Backlog / GitLab / Bitbucket などのリポジトリでは出ません。GitHub をメインに使っている方には便利な追加項目です。 - コード変更行数:
cost.total_lines_added/total_lines_removed。セッション内で何行触ったか可視化できます。 - コンテキスト上限:
context_window.context_window_size。200k / 1M どちらのモデルか確認できます。 - API 待ち時間 vs 総経過時間:
cost.total_api_duration_ms/total_duration_ms。セッションのうち AI レスポンス待ちに使った割合が分かります。 - GitHub リポジトリ識別子:
workspace.repo.host/owner/name。OSC 8 でリポジトリへのリンクを張るのに使えます。 - worktree モードの情報:
worktree.name/branch/original_branch。--worktreeセッションを並行運用しているときに役立ちます。 - サブエージェント名:
agent.name。--agentで起動したセッションかどうか分かります。 - vim モード:
vim.mode。vim キーバインドを使う方向け。
また、git status / git diff のような重い操作を毎回呼ぶとレイテンシ要因になるので、複数行構成にしてさらに git 情報を増やす場合は、公式ドキュメントのキャッシング例 を参考に session_id をキーにしたファイルキャッシュを入れるのがおすすめです。
まとめ
Claude Codeに渡されるステータス情報をstatuslineを組んでみました。/statusを叩いたりレート通知を待ったりしていた操作が不要になり、視野の隅で常に把握できるようになったので、長時間作業時の判断スピードがかなり改善しました。
Claude Codeの初期セットアップを実施している方にとって参考になれば幸いです。








