Claude Codeの使用率がステータスラインに表示できるようになったので表示用のスクリプトを作った話
by 逆瀬川ちゃん
7 min read
こんにちは!逆瀬川 (@gyakuse) です!
Claude Code v2.1.80で待ちに待ったステータスライン用のrate_limitsフィールドが追加されました。これがないために本当にみんな頑張ってきたのです。本当につらい世界でした。
何が変わったのか
2026年3月19日リリースのv2.1.80で、ステータスラインに渡されるJSONにrate_limitsフィールドが追加されました。
changelogの記載はこうです。
Added rate_limits field to statusline scripts for displaying Claude.ai rate limit usage (5-hour and 7-day windows with used_percentage and resets_at)
これにより、Claude Codeのサブスクリプションの使用量(5時間ウィンドウと7日間ウィンドウ)をステータスラインにリアルタイムで表示できるようになりました。
仕組み
Claude Codeのステータスラインはシンプルな仕組みで動いています。
- Claude Codeがセッション情報をJSONとしてスクリプトの標準入力に渡す
- スクリプトが必要なフィールドを取り出して整形する
- 標準出力に出した文字列がそのままステータスバーに表示される
今回追加されたrate_limitsフィールドはこんな構造です。
{
"rate_limits": {
"five_hour": {
"used_percentage": 42.3,
"resets_at": "2026-03-20T15:00:00Z"
},
"seven_day": {
"used_percentage": 85.7,
"resets_at": "2026-03-24T00:00:00Z"
}
}
}
used_percentageが使用率、resets_atがリセット時刻です。既存のcontext_window.used_percentage(コンテキストウィンドウの使用率)と合わせて表示すれば、残りリソースが一目でわかります。
設定方法
~/.claude/settings.jsonにstatusLineを追加するだけです。
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.py"
}
}
スクリプトはchmod +xで実行権限をつけておく必要があります。
5つのビジュアルパターン
せっかくなのでいくつかパターンを作ってみました。すべてのパターンで以下の情報を表示しています。
- ctx: コンテキストウィンドウの使用率
- 5h: 5時間ウィンドウの使用率
- 7d: 7日間ウィンドウの使用率
色はすべてTrueColorグラデーションで、使用率に応じて緑→黄→赤に連続的に変化します。
Pattern 1: Minimal Dots
カラードットと数値だけのミニマルなスタイルです。

情報密度は低いですがすっきりしていて、ステータスバーのスペースをあまり取りません。
Pattern 2: Sparkline Gauge
ブロック要素を使ったスパークラインスタイルです。

縦方向の高さで使用率を表現するので、横幅が抑えられます。
Pattern 3: Ring Meter
円グラフ風アイコンを使ったスタイルです。

もっともコンパクトなパターンです。5段階の粗い表現ですが、色と組み合わせれば十分実用的です。
Pattern 4: Fine Bar + Gradient
1%精度の細密プログレスバーです。

もっとも情報量が多く視覚的にも映えるパターンです。
Pattern 5: Braille Dots
点字パターンを使ったドットスタイルです。

ドットの密度で使用率を表現します。レトロな雰囲気があって個人的にはこれを使っています。
まとめ
- Claude Code 2.1.80で
rate_limitsフィールドが追加され、5時間/7日間の使用量をステータスラインに表示できるようになった - ANSIカラーやUnicodeブロック要素を使えばかなり綺麗に表示できる
- スクリプトはAppendixにコピペで使える形で載せているので好きなパターンを選んでください
- Claude Codeを使えばサクッといい感じのスクリプトを出せて、見ながら調節できるので、みんなも自分用のステータスラインをカスタマイズしていきましょう!
Appendix: スクリプト全文
すべてPythonスクリプトです。~/.claude/statusline.pyとして保存し、chmod +xで実行権限を付与してください。
Pattern 1: Minimal Dots
#!/usr/bin/env python3
"""Pattern 1: Minimal dots - colored circles with numbers only"""
import json, sys
data = json.load(sys.stdin)
R = '\033[0m'
DIM = '\033[2m'
BOLD = '\033[1m'
def gradient(pct):
if pct < 50:
r = int(pct * 5.1)
return f'\033[38;2;{r};200;80m'
else:
g = int(200 - (pct - 50) * 4)
return f'\033[38;2;255;{max(g, 0)};60m'
def dot(pct):
p = round(pct)
return f'{gradient(pct)}●{R} {BOLD}{p}%{R}'
model = data.get('model', {}).get('display_name', 'Claude')
parts = [f'{BOLD}{model}{R}']
ctx = data.get('context_window', {}).get('used_percentage')
if ctx is not None:
parts.append(f'ctx {dot(ctx)}')
five = data.get('rate_limits', {}).get('five_hour', {}).get('used_percentage')
if five is not None:
parts.append(f'5h {dot(five)}')
week = data.get('rate_limits', {}).get('seven_day', {}).get('used_percentage')
if week is not None:
parts.append(f'7d {dot(week)}')
print(f' {DIM}·{R} '.join(parts), end='')
Pattern 2: Sparkline Gauge
#!/usr/bin/env python3
"""Pattern 2: Sparkline gauge - vertical block characters"""
import json, sys
data = json.load(sys.stdin)
SPARKS = ' ▁▂▃▄▅▆▇█'
R = '\033[0m'
DIM = '\033[2m'
def gradient(pct):
if pct < 50:
r = int(pct * 5.1)
return f'\033[38;2;{r};200;80m'
else:
g = int(200 - (pct - 50) * 4)
return f'\033[38;2;255;{max(g, 0)};60m'
def spark_gauge(pct, width=8):
pct = min(max(pct, 0), 100)
level = pct / 100
gauge = ''
for i in range(width):
seg_start = i / width
seg_end = (i + 1) / width
if level >= seg_end:
gauge += SPARKS[8]
elif level <= seg_start:
gauge += SPARKS[0]
else:
frac = (level - seg_start) / (seg_end - seg_start)
gauge += SPARKS[int(frac * 8)]
return gauge
def fmt(label, pct):
p = round(pct)
return f'{DIM}{label}{R} {gradient(pct)}{spark_gauge(pct)}{R} {p}%'
model = data.get('model', {}).get('display_name', 'Claude')
parts = [model]
ctx = data.get('context_window', {}).get('used_percentage')
if ctx is not None:
parts.append(fmt('ctx', ctx))
five = data.get('rate_limits', {}).get('five_hour', {}).get('used_percentage')
if five is not None:
parts.append(fmt('5h', five))
week = data.get('rate_limits', {}).get('seven_day', {}).get('used_percentage')
if week is not None:
parts.append(fmt('7d', week))
print(f' {DIM}│{R} '.join(parts), end='')
Pattern 3: Ring Meter
#!/usr/bin/env python3
"""Pattern 3: Ring meter - pie-like circle segments"""
import json, sys
data = json.load(sys.stdin)
R = '\033[0m'
DIM = '\033[2m'
BOLD = '\033[1m'
RINGS = ['○', '◔', '◑', '◕', '●']
def gradient(pct):
if pct < 50:
r = int(pct * 5.1)
return f'\033[38;2;{r};200;80m'
else:
g = int(200 - (pct - 50) * 4)
return f'\033[38;2;255;{max(g, 0)};60m'
def ring(pct):
idx = min(int(pct / 25), 4)
return RINGS[idx]
def fmt(label, pct):
p = round(pct)
return f'{DIM}{label}{R} {gradient(pct)}{ring(pct)} {p}%{R}'
model = data.get('model', {}).get('display_name', 'Claude')
parts = [f'{BOLD}{model}{R}']
ctx = data.get('context_window', {}).get('used_percentage')
if ctx is not None:
parts.append(fmt('ctx', ctx))
five = data.get('rate_limits', {}).get('five_hour', {}).get('used_percentage')
if five is not None:
parts.append(fmt('5h', five))
week = data.get('rate_limits', {}).get('seven_day', {}).get('used_percentage')
if week is not None:
parts.append(fmt('7d', week))
print(' '.join(parts), end='')
Pattern 4: Fine Bar + Gradient
#!/usr/bin/env python3
"""Pattern 4: Fine-grained progress bar with true color gradient"""
import json, sys
data = json.load(sys.stdin)
BLOCKS = ' ▏▎▍▌▋▊▉█'
R = '\033[0m'
DIM = '\033[2m'
def gradient(pct):
if pct < 50:
r = int(pct * 5.1)
return f'\033[38;2;{r};200;80m'
else:
g = int(200 - (pct - 50) * 4)
return f'\033[38;2;255;{max(g,0)};60m'
def bar(pct, width=10):
pct = min(max(pct, 0), 100)
filled = pct * width / 100
full = int(filled)
frac = int((filled - full) * 8)
b = '█' * full
if full < width:
b += BLOCKS[frac]
b += '░' * (width - full - 1)
return b
def fmt(label, pct):
p = round(pct)
return f'{label} {gradient(pct)}{bar(pct)} {p}%{R}'
model = data.get('model', {}).get('display_name', 'Claude')
parts = [model]
ctx = data.get('context_window', {}).get('used_percentage')
if ctx is not None:
parts.append(fmt('ctx', ctx))
five = data.get('rate_limits', {}).get('five_hour', {}).get('used_percentage')
if five is not None:
parts.append(fmt('5h', five))
week = data.get('rate_limits', {}).get('seven_day', {}).get('used_percentage')
if week is not None:
parts.append(fmt('7d', week))
print(f'{DIM}│{R}'.join(f' {p} ' for p in parts), end='')
Pattern 5: Braille Dots
#!/usr/bin/env python3
"""Pattern 5: Braille dots - dotted progress bar using braille characters"""
import json, sys
data = json.load(sys.stdin)
BRAILLE = ' ⣀⣄⣤⣦⣶⣷⣿'
R = '\033[0m'
DIM = '\033[2m'
def gradient(pct):
if pct < 50:
r = int(pct * 5.1)
return f'\033[38;2;{r};200;80m'
else:
g = int(200 - (pct - 50) * 4)
return f'\033[38;2;255;{max(g, 0)};60m'
def braille_bar(pct, width=8):
pct = min(max(pct, 0), 100)
level = pct / 100
bar = ''
for i in range(width):
seg_start = i / width
seg_end = (i + 1) / width
if level >= seg_end:
bar += BRAILLE[7]
elif level <= seg_start:
bar += BRAILLE[0]
else:
frac = (level - seg_start) / (seg_end - seg_start)
bar += BRAILLE[min(int(frac * 7), 7)]
return bar
def fmt(label, pct):
p = round(pct)
return f'{DIM}{label}{R} {gradient(pct)}{braille_bar(pct)}{R} {p}%'
model = data.get('model', {}).get('display_name', 'Claude')
parts = [model]
ctx = data.get('context_window', {}).get('used_percentage')
if ctx is not None:
parts.append(fmt('ctx', ctx))
five = data.get('rate_limits', {}).get('five_hour', {}).get('used_percentage')
if five is not None:
parts.append(fmt('5h', five))
week = data.get('rate_limits', {}).get('seven_day', {}).get('used_percentage')
if week is not None:
parts.append(fmt('7d', week))
print(f' {DIM}│{R} '.join(parts), end='')