Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungLarge AI Labs Face Regulatory Capture Allegations(21.09.2026 um 05:18 Uhr)
Sichere ProgrammierungWhat people are building with Jev: a look through nine awesome lists(21.09.2026 um 05:44 Uhr)
IT Security Toolsnetwatch v0.32.3(21.09.2026 um 04:36 Uhr)
Sichere ProgrammierungLarge AI Labs Face Regulatory Capture Allegations(21.09.2026 um 05:18 Uhr)
Sichere ProgrammierungWhat people are building with Jev: a look through nine awesome lists(21.09.2026 um 05:44 Uhr)
IT Security Toolsnetwatch v0.32.3(21.09.2026 um 04:36 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Always-On Cost and Plan-Quota Visibility for Claude Code: Building a Statusline

Reagiere als Erste:r — dein Feedback zählt!

In my last post, "Letting Claude Code improve itself autonomously — autopilot", I covered how to keep autopilot from running away, but I glossed over the part about "surfacing your plan quota in the statusline" in a single paragraph. This time I'll walk through that implementation in full.

No auth, no endpoint calls. All you do is read the JSON that Claude Code passes to the statusline script over stdin with jq, and you get your 5h/7d plan quota, context usage, and session cost plus today's running total (converted to yen) always visible in three lines.

The problem: consumption that surprises you "later"

Claude Max's API has soft rate limits. As your output tokens approach the cap within a 5-hour block or a 7-day window, the model's behavior changes, and once you burn through it, subsequent slots get skipped. The problem is that you usually can't see this consumption.

  • "Did the model's replies just get thinner?" → turns out your 5h quota was full
  • You start a manual session without realizing autopilot's background usage is being counted in too
  • Your sense of cost drifts, and you only grasp the situation at month-end when you check ccusage

The "open a dashboard in a separate tab" approach dies within three days. If the numbers are always on your working screen, the remaining quota catches your eye without you having to think about it.

Values you can pull straight from stdin

Every time Claude Code launches the statusline script, it streams JSON to stdin. Almost everything you need is already there.

# ~/.claude/scripts/statusline.sh
INPUT="$(cat 2>/dev/null || echo '{}')"

j() { printf '%s' "$INPUT" | jq -r "$1" 2>/dev/null; }

CTX=$(j '.context_window.used_percentage // empty')
H5=$(j '.rate_limits.five_hour.used_percentage // empty')
H5R=$(j '.rate_limits.five_hour.resets_at // empty')
D7=$(j '.rate_limits.seven_day.used_percentage // empty')
D7R=$(j '.rate_limits.seven_day.resets_at // empty')
SESSION_USD=$(j '.cost.total_cost_usd // 0')

.context_window.used_percentage is a value Claude Code precomputes and hands you, so you don't have to count tokens yourself. rate_limits only appears after a subscription user has received their first API response, so without the // empty fallback you'll get an error right at the start of a session.

rate_limits only appears "after the first API response, and only on a subscription." Right after startup, fall back to a -- display; the numbers start showing once the first turn comes back.

Reset times arrive as epoch seconds, so convert them to local time with date.

clk()  { [ -n "$1" ] && date -r "$1" "+%H:%M" 2>/dev/null; }         # → HH:MM
mdhm() { [ -n "$1" ] && date -r "$1" "+%-m/%-d %H:%M" 2>/dev/null; } # → M/D HH:MM

Three-line layout

The output is a fixed three-line structure.

line1: 📁 dir   ⌥ branch
line2: 🤖 model·effort   🧠 ctx%   🕐 5h N% ⏪HH:MM   📅 7d N% ⏪M/D HH:MM
line3: 💴 session ≈¥x   今日 ≈¥y   <health>

The actual format calls look like this.

L2=$(printf "${MAG}🤖 %s%s${R}  ${DIM}·${R}  ${CTXC}🧠 ctx %s${R}  ${DIM}·${R}  ${C5}🕐 5h %s${R}%b  ${DIM}·${R}  ${C7}📅 7d %s${R}%b" \
  "$MODEL" "$EFF" "$(pct "$CTX")" "$(pct "$H5")" "$R5" "$(pct "$D7")" "$R7")
L3=$(printf "${DIM}💴 session${R} %s   ${DIM}今日${R} %s  %s%b" \
  "$(yen "$SESSION_USD")" "$(yen "$DAY_USD")" "$HEALTH" "$PROJ_HEALTH_SEG")

The percentages are color-coded, so you can read the state without reading the numbers.

# pct -> color (green <50, yellow 50-79, red >=80)
pcolor() { local n="${1%%.*}"; [ -z "$n" ] && { printf '%s' "$DIM"; return; }
  if [ "$n" -ge 80 ] 2>/dev/null; then printf '%s' "$RED"
  elif [ "$n" -ge 50 ] 2>/dev/null; then printf '%s' "$YEL"
  else printf '%s' "$GRN"; fi; }

Getting today's cost with a 2-minute cache

SESSION_USD comes straight from stdin in real time, but "today's total cost" requires ccusage's daily aggregation. Calling it every time would stall the statusline render, so I use a 2-minute cache plus a background refresh.

CCUSAGE=$(command -v ccusage 2>/dev/null || echo "$HOME/.nvm/versions/node/v24.13.0/bin/ccusage")
DAY_CACHE="/tmp/cc-daily-cache.json"
NEED=true
if [ -f "$DAY_CACHE" ]; then
  AGE=$(($(date +%s) - $(stat -f %m "$DAY_CACHE" 2>/dev/null || echo 0)))
  [ "$AGE" -lt 120 ] && NEED=false
fi
[ "$NEED" = true ] && ( "$CCUSAGE" daily --json 2>/dev/null > "${DAY_CACHE}.tmp" && mv "${DAY_CACHE}.tmp" "$DAY_CACHE" ) &
DAY_USD=0
if [ -f "$DAY_CACHE" ]; then
  TODAY=$(date "+%Y-%m-%d")
  DAY_USD=$(jq -r --arg d "$TODAY" '(.daily[] | select(.date==$d) | .totalCost) // (.daily[-1].totalCost) // 0' "$DAY_CACHE" 2>/dev/null)
fi

The key point is throwing it into a subshell with &. Even when the cache has expired, the statusline returns the old value at that instant and runs ccusage in the background. A number that's 2 minutes stale causes no practical problems in real use.

The yen conversion is a one-line awk using a rate set at the top.

JPY_RATE=150   # Edit to taste / use $ instead.

yen() { awk -v u="$1" -v r="$JPY_RATE" 'BEGIN{
  v=u*r; n=sprintf("%.0f", v); s=""; len=length(n); c=0
  for(i=len;i>=1;i--){ s=substr(n,i,1) s; c++; if(c%3==0 && i>1) s="," s }
  printf "¥%s", s }'; }

It displays with comma separators every three digits, like ¥1,234. If you prefer dollars, just change the spots where yen is called to use $SESSION_USD directly.

A one-character health indicator (5-minute cache)

At the end of L3, I show automation liveness as a single 🟢/🟡/🔴/⚫ character. Because automation-health.sh is expensive to launch, this one uses a 5-minute cache.

HEALTH_CACHE="/tmp/cc-health-cache"; HEALTH=""
if [ -f "$HEALTH_CACHE" ]; then
  HAGE=$(($(date +%s) - $(stat -f %m "$HEALTH_CACHE" 2>/dev/null || echo 0)))
  [ "$HAGE" -lt 300 ] && HEALTH=$(cat "$HEALTH_CACHE" 2>/dev/null)
fi
if [ -z "$HEALTH" ]; then
  ( h=$(~/.claude/scripts/automation-health.sh 2>&1 | grep -oE "ALL GREEN|WARN|FAIL" | head -1)
    case "$h" in
      "ALL GREEN") echo "🟢" > "$HEALTH_CACHE" ;;
      "WARN")      echo "🟡" > "$HEALTH_CACHE" ;;
      "FAIL")      echo "🔴" > "$HEALTH_CACHE" ;;
      *)           echo "⚫" > "$HEALTH_CACHE" ;;
    esac ) &
  HEALTH="·"
fi

When the cache has expired, it returns · (a dot) while kicking off a background refresh. If the cache is ready by the next render cycle, it switches to the emoji. The statusline render must never block under any circumstances — that's the core of the design.

token-budget-advisor.sh: precise cross-validation

The statusline display is meant to visualize "roughly where I am right now." For autopilot to decide whether to "run or stop," you need precision, and that role falls to token-budget-advisor.sh.

It prefers ccusage's official block aggregation, but also computes its own aggregation from ~/.claude/logs/cost-log.jsonl, calculating both and emitting the difference rate (source_diff_pct).

# ccusage が居れば5hブロックのoutput tokenを取る(transcript計算より公式)
if command -v ccusage >/dev/null 2>&1; then
  CC_JSON=$(ccusage blocks --json 2>/dev/null || true)
  # ... activeブロックを抽出してoutputTokens/costUSDを取り出す
  CC_OUTPUT_TOK="${EXTRACTED%|*}"
  CC_COST_5H="${EXTRACTED#*|}"
fi

The decision thresholds are set like this.

THRESH_5H_WARN      = 800_000   # output tokens → warn
THRESH_5H_CRIT      = 1_200_000 # → critical
THRESH_WEEK_WARN    = 3000      # USD / 7d
THRESH_SESS_PER_DAY = 5         # 直近3d平均 > 5 → burst

In --short mode it produces one-line output, which autopilot reads to make its call ahead of time.

# autopilot側のコードより(前作で紹介)
BUDGET=$(~/.claude/scripts/token-budget-advisor.sh --short)
if echo "$BUDGET" | grep -qE '🔴|critical|cap-near'; then
  log "ABORT: budget critical"; exit 0
fi

In the autopilot post I described an incident where "a negative remaining slipped through because only the label was checked." For that reason, token-budget-advisor.sh recomputes the remaining amount numerically, separately from the label, and stops if it's 0 or below — a double check.

cost-summary.sh: aggregation by period

~/.claude/scripts/cost-summary.sh           # 7日分(デフォルト)
~/.claude/scripts/cost-summary.sh 30        # 30日分
~/.claude/scripts/cost-summary.sh today     # 今日だけ

per day: visualizes usage with a Unicode bar graph.

bar = "" * min(40, int(d["cost"] * 4))
print(f"    {day}: ${d['cost']:5.2f} ({d['n']}s) {bar}")

per model: also breaks down message counts by model. I use it to look back on "what did I do on days with lots of Sonnet."

Pitfalls I hit

  • rate_limits doesn't exist right after a session starts → fall back with // empty. A -- display is normal until the first turn returns
  • ccusage daily blocks the statusline → 120-second cache plus & to make it async. Even when stale, the render never stops
  • The health check is heavy every time → 5-minute cache plus &. While refreshing, it just returns ·
  • I didn't notice the divergence between ccusage and my own aggregation → I emit source_diff_pct so cross-validation is always possible
  • stat -f %m is macOS-only → on Linux, change it to stat -c %Y. The script is written assuming macOS
  • I mistakenly thought there was no rate_limits and tried to hit an endpoint → putting a line that dumps the stdin JSON to a debug log (/tmp/cc-statusline-last.json) in from the start helps you catch this sooner
# デバッグ用。消してもよい
printf '%s' "$INPUT" > /tmp/cc-statusline-last.json 2>/dev/null || true

Wrap-up

  • Claude Code's statusline script receives .rate_limits.* / .context_window.used_percentage / .cost.total_cost_usd on stdin. No auth needed
  • Three lines give you an always-on view of "branch / 5h・7d・ctx% / session + today's cost in yen plus health"
  • Today's cost uses a 2-minute cache plus background refresh so it never blocks
  • The one-character health indicator is lightened with a 5-minute cache
  • token-budget-advisor.sh cross-validates ccusage's official values against its own aggregation and feeds autopilot's run/stop decision

Next up, building on this statusline and autopilot's monitoring, I'm writing about having Claude Code patrol GitHub every morning to automatically score useful OSS and skillsHaving Claude Code patrol GitHub every morning — auto-scoring useful OSS and skills.

Written by **Lily* — I ship iOS apps and automate my content stack with Claude Code.
Follow along: Portfolio · X · GitHub*

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Always-On Cost and Plan-Quota Visibility for Claude Code: Building a Statusline

Thematisch verwandte Begriffe: AlwaysOn, Cost, PlanQuota, Visibility · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94104 | NivoCart through 2.4.0 contains an arbitrary file upload vulnerability i…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick