Claude Code Statusline: monitoring your rate limits in real time

Claude Code rate-limits its users. Not brutally — with overlapping quotas: active context window size, session quota, weekly quota, per-model quotas. The problem: no visibility without typing /usage in the interface, which means breaking out of the workflow, reading formatted text, memorizing numbers, and resuming. During an intense development session, this happens often, and it's always at the worst moment.

The initial idea was simple: the equivalent of a tmux powerline, but for Claude Code quotas. A bar at the bottom of the screen, always there, updated in the background. Result: a Bash script, built with Claude Code itself during a single session, that displays claude code rate limit status information permanently without ever blocking the active terminal.

What it displays

In practice, the bar looks like this:

🌿 main │ 🤖 Sonnet 4.6 │ 🟢 Ctx ▓▓░░░░░░ 34% │ ⏳ 🟡 ▓▓▓░░░░░ 46% → 19h00 (3h20m) │ 📅 🟡 42% / Snt 🔴 59% ↻ Mon 14h 🔄 5m

Each segment has its function:

  • 🌿 main — current git branch of the active directory
  • 🤖 Sonnet 4.6 — active model in the Claude Code session
  • 🟢 Ctx ▓▓░░░░░░ 34% — percentage of the context window consumed
  • ⏳ 🟡 ▓▓▓░░░░░ 46% → 19h00 (3h20m) — session quota: current usage, reset time, time remaining until that reset
  • 📅 🟡 42% / Snt 🔴 59% ↻ Mon 14h — global weekly quota and Sonnet-specific weekly quota, with the day and time of reset
  • 🔄 5m — time since last data refresh

The color coding follows a simple rule: green below 50%, yellow between 50 and 80%, red beyond that. It's enough to know at a glance whether you can afford a long refactoring or whether you should finish the current task and wait for the reset.

The architecture: two paths, one command

The interesting part. Claude Code accepts a statusLine key in ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/hooks/statusline.sh"
  }
}

Claude Code calls this command on every status bar refresh and displays what the script writes to stdout. The constraint: this path must be fast. A synchronous network call here freezes the interface. The solution is a split into two distinct paths.

The fast path (called on every refresh): the script reads ~/.claude/usage-exact.json and formats the data as text. It's a local file read — near-instantaneous, no perceptible latency.

The slow path (every 10 minutes, in the background): the script launches a detached tmux session named claude-usage-bg, opens a new Claude Code instance inside it, automatically executes /usage, parses the text output with regex, and writes the result to ~/.claude/usage-exact.json.

Why tmux? Claude Code is an interactive CLI, not a scriptable API. There's no --quiet or --json mode to retrieve usage data programmatically. The only way to spawn a new instance without blocking the active session is to isolate it in a detached tmux session. A lock file at /tmp/claude-usage-refresh.lock prevents duplicate scrapers. A 120-second timeout kills zombie processes if something goes wrong.

This is the cache-first pattern applied to a status bar: rendering always reads from cache, cache updates happen outside the critical path. Never block on a network call or external process to display a status bar.

Parsing text with regex

There's no API for Claude Code's /usage data. The output is human-readable text, formatted for a terminal. So we parse text with regex — not elegant, but it's what we have.

The overall logic: capture the output of /usage via tmux capture-pane, extract numbers and times by pattern matching, convert reset times to timestamps. One undocumented detail that costs debugging time: Claude Code displays reset times in the machine's local timezone, without indicating it explicitly. The script automatically detects the timezone from the output itself and adjusts the countdown calculation accordingly. Without this, the counter is off by the UTC offset whenever you're not in UTC.

The other real-world detail: when automating the Claude Code CLI, opening a new session sometimes displays a trust prompt ("Trust this directory?") that blocks execution. This case must be handled explicitly in the script — sending the expected response via tmux send-keys before sending the /usage command. This kind of edge case is nowhere in the documentation.

Installation

curl -fsSL https://raw.githubusercontent.com/ohugonnot/claude-code-statusline/main/install.sh | bash

The installer does, in order:

  1. Checks dependencies: jq, tmux, python3
  2. Offers to install them via apt or brew if missing
  3. Copies the script to ~/.claude/hooks/statusline.sh
  4. Patches ~/.claude/settings.json non-destructively with jq — existing keys are not overwritten

The refresh interval is configurable: bash install.sh --refresh 300 for an update every 5 minutes instead of 10.

What we learned building it

Claude Code is a tool for humans. Automating it requires handling interactive prompts, timeouts, race conditions between sessions. It's not an API — it's a CLI that assumes a human operator. As soon as you try to script it, you hit edge cases that nothing in the docs anticipates.

The cache-first pattern is the only viable one for a status bar. Any architecture that blocks the render path on a network call or external process produces a frozen or slow interface. Local cache with asynchronous updates is the only option that stays responsive regardless of the slow path's latency.

Building a Claude Code tool with Claude Code tests its own limits. We hit the rate limit several times during development — which is both ironic and useful. It makes concrete what you're trying to monitor, and it forces you to think about the experience of a user approaching their quotas.

tmux as a process isolation bus: not elegant, but reliable. The clean solution would be an API. In the absence of an API, you use the right tool for the real job — not the ideal job. tmux isolates an interactive process, captures its output, and lets it run outside the active terminal. That's exactly what was needed.

Conclusion

The project is open source, MIT, available at github.com/ohugonnot/claude-code-statusline . One-line install. If you use Claude Code heavily, you know the frustration of hitting a quota without seeing it coming — right in the middle of a refactoring, just when the agent had finally understood the context. This script makes the limits visible before they're reached. That's all it does, and that's enough.

Comments (0)