はじめに / 対象と前提
Claude Code で長いセッションを回していると、「今コンテキストをどれだけ食っているか」「このセッションいくら使ったか」が気になる。/context や /cost を毎回叩くのは面倒なので、画面下部の ステータスライン(statusLine) に常時出すようにした。
この記事は、Claude Code を日常的に使っていて、シェルスクリプトが書ける人向け。設定の書き方、stdin で渡ってくる JSON の中身、実際にハマった 3 点をまとめる。
検証環境:
- Claude Code v2.1.274(macOS 15 / zsh)
- jq 1.7.1
- Node.js 23.x(Node 版スクリプトの動作確認用)
TL;DR
-
~/.claude/settings.jsonにstatusLine.commandを書くと、Claude Code が 任意のシェルコマンドを実行し、stdout をそのまま画面下に表示する - 入力は stdin の JSON 1 発。
model.display_name/context_window.used_percentage/cost.total_cost_usdあたりを拾えば実用十分 - ハマりどころは null 対策・端末幅の取り方・毎回走ることを忘れた重い処理 の 3 つ
手順 / 動かし方
1. スクリプトを置く
~/.claude/statusline.sh を作る。モデル名・作業ディレクトリ・コンテキスト使用率のバー・セッションコストを 1 行に出す最小構成。
#!/bin/bash
# Claude Code が stdin に流してくる JSON を丸ごと受ける
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
# null のことがあるので // 0 でフォールバック(後述)
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
# 10 マスのバーを組む
FILLED=$((PCT / 10)); EMPTY=$((10 - FILLED))
printf -v FILL "%${FILLED}s"; printf -v PAD "%${EMPTY}s"
BAR="${FILL// /▓}${PAD// /░}"
# 70% 超えたら黄色、90% 超えたら赤
COLOR="\033[32m"
[ "$PCT" -ge 70 ] && COLOR="\033[33m"
[ "$PCT" -ge 90 ] && COLOR="\033[31m"
printf "[%s] %s ${COLOR}%s %s%%\033[0m \$%.2f\n" \
"$MODEL" "${DIR##*/}" "$BAR" "$PCT" "$COST"
実行権限を忘れずに。
chmod +x ~/.claude/statusline.sh
2. settings.json に登録する
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 0
}
}
保存すると 再起動なしで即反映される。padding は左右の余白(文字数)で省略可。
3. 手元で単体テストする
Claude Code を起動しなくても、JSON を流し込めば動作確認できる。
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/tmp/demo"},
"context_window":{"used_percentage":42},"cost":{"total_cost_usd":0.1234}}' \
| ~/.claude/statusline.sh
出力:
[Opus] demo ▓▓▓▓░░░░░░ 42% $0.12
ここまでで実際の Claude Code 画面下にも同じ行が出た。
4. 渡ってくる JSON の主なフィールド
自分が使ったものだけ抜粋。全量は公式ドキュメントの Available data を参照。
| フィールド | 中身 |
|---|---|
model.id / model.display_name
|
モデル ID と表示名 |
workspace.current_dir / workspace.project_dir
|
現在 cwd と起動時ディレクトリ(cd で乖離しうる) |
context_window.used_percentage |
コンテキスト使用率(入力トークンのみで計算) |
context_window.current_usage |
直近 API 呼び出しの input_tokens / cache_read_input_tokens などの内訳 |
cost.total_cost_usd |
セッション累計コスト(定価ベースの推定値) |
cost.total_lines_added / total_lines_removed
|
変更行数 |
rate_limits.five_hour.used_percentage |
5 時間枠の消費率(Pro/Max のみ、初回応答後に出現) |
vim.mode |
vim モード有効時のみ |
いつ再実行されるかも把握しておくと設計しやすい。セッション開始時に 1 回、その後は アシスタントのメッセージ到着・/compact 完了・permission モード変更 などのイベントごとに走る。連打は 300ms でデバウンスされる。
ハマりどころ
1. used_percentage が null で算術展開が落ちる
最初は // 0 を付けずに書いていて、セッション開始直後にステータスラインが空になった。原因は 最初の API 呼び出しが終わるまで context_window.used_percentage と current_usage が null なこと。jq -r は null を文字列 null で吐くので、$((PCT / 10)) が null: syntax error になって bash が非ゼロ終了し、何も表示されない。
さらに /compact 直後も current_usage は一度 null に戻る。「起動時だけガードすればいい」ではなく、常に // 0 を噛ませる。
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
rate_limits や vim のように キー自体が存在しないフィールドは // empty にして、無いときは表示しないのが素直。
2. tput cols が端末幅を返さない
長い行を端末幅で切り詰めようとして tput cols を使ったら、常に 80 が返ってきた。Claude Code は スクリプトの stdout を捕捉して自前描画しているので、スクリプトから見ると tty に繋がっていない。Python の shutil.get_terminal_size() も同じ理由でデフォルト値を返す。
Claude Code 側が環境変数 COLUMNS と LINES を渡してくれるので、そちらを読む。
WIDTH=${COLUMNS:-80}
LINE="[$MODEL] ${DIR##*/} $BAR $PCT% \$$COST"
printf "%.${WIDTH}s\n" "$LINE"
3. git status を毎回叩いたら入力がもたつく
ブランチ名とダーティ状態を出したくて git status --porcelain を無邪気に入れたら、大きめのモノレポで メッセージが来るたびに数百 ms 固まるようになった。ステータスラインは「たまに動くもの」ではなく イベントのたびに走るので、重い処理はキャッシュ前提で書く。
自分は結果を /tmp に落として 5 秒だけ使い回す形にした。
CACHE="/tmp/claude-sl-git-$(echo "$DIR" | md5 -q)"
if [ ! -f "$CACHE" ] || [ $(( $(date +%s) - $(stat -f %m "$CACHE") )) -gt 5 ]; then
(cd "$DIR" && {
BR=$(git symbolic-ref --short HEAD 2>/dev/null || echo "-")
[ -n "$(git status --porcelain 2>/dev/null | head -1)" ] && BR="$BR*"
echo "$BR"
}) > "$CACHE" 2>/dev/null
fi
GIT=$(cat "$CACHE")
Linux なら md5 -q を md5sum | cut -d' ' -f1、stat -f %m を stat -c %Y に読み替える。
背景・補足
-
used_percentageは入力トークンのみで計算される(input_tokens + cache_creation_input_tokens + cache_read_input_tokens)。自分でcurrent_usageから計算するならoutput_tokensを足さないこと。足すと公式値と食い違う -
複数行出力もできる。
echoを 2 回すれば 2 行になる。1 行目に git 情報、2 行目にバーという構成が見やすかった - ANSI カラーはそのまま通る。ただし permission プロンプトやヘルプ表示中は一時的に隠れる仕様
-
/statuslineコマンドに自然言語で頼めば、上記相当のスクリプトと設定を Claude Code が自動生成する。まずそれで叩き台を作って手で直すのが速い - スクリプトはローカル実行なので API トークンは消費しない
-
prompt_cache(キャッシュヒット率など)は v2.1.251 以降でしか流れてこない。古いバージョンでnull参照して落とさないよう注意
まとめ
-
statusLine.commandに任意スクリプトを登録するだけで、Claude Code の画面下に好きな情報を常時表示できる - stdin の JSON は セッション初期と
/compact直後にnullが混ざる。// 0/// emptyを常に付ける - 端末幅は
tput colsではなくCOLUMNS環境変数で取る - スクリプトは イベントごとに毎回走る。
git statusなどの重い処理はキャッシュする - 迷ったらまず
/statuslineで生成してから手で育てるのが楽