Claude Codeのstatuslineをカスタマイズしてセッションのステータス状況を見える化する

Claude Codeのstatuslineをカスタマイズしてセッションのステータス状況を見える化する

2026.05.29

はじめに

データ事業本部の荒木です。

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.jsonstatusLine セクションに、作成したスクリプトのパスを書きます。

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/scripts/statusline.sh",
    "padding": 1
  }
}

オプションの padding は左右の余白で、デフォルト 0 です。refreshInterval を秒数指定すると、イベント駆動更新に加えて N 秒ごとにスクリプトを再実行できますが、本記事の構成ではイベント駆動だけで十分です。

動作確認

設定後のカスタムstatuslineが出力されるとこんな感じです。

画像1

コンテキスト残量が 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 にしか対応していない (内部的に gh CLI 経由で取得しているため) ので、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の初期セットアップを実施している方にとって参考になれば幸いです。

参照


生成AI活用はクラスメソッドにお任せ

過去に支援してきた生成AIの支援実績100+を元にホワイトペーパーを作成しました。御社が抱えている課題のうち、どれが解決できて、どのようなサービスが受けられるのか?4つのフェーズに分けてまとめています。どうぞお気軽にご覧ください。

生成AI資料イメージ

無料でダウンロードする

この記事をシェアする

関連記事