Claude Code monitor tools: the terminal options compared

If you live in a terminal, you want the monitor there too. There are four approaches that work, and the best of them costs one line of config, no screen space, and no attention, because it renders into a surface you are already looking at.

By the Continuum team. We build a workbench that runs Claude Code, Codex, and their peers, so the model rates quoted here are the ones our own cost analytics ship with.

The short version

Terminal monitoring for Claude Code comes down to four options: a status line command you write yourself, the ccusage statusline command, the Claude Code Usage Monitor TUI, and ccusage blocks --active in a spare pane. The status line route is the only one that costs no screen space, and since Claude Code pipes rate_limits to it, it is also the only zero-attention way to see remaining plan quota.

What you need to know
  • A status line command puts live quota in your prompt at zero attention cost.
  • Claude Code pipes rate_limits.five_hour and seven_day to that command on stdin.
  • bunx ccusage statusline is the no-code version, showing spend and burn rate.
  • TUI monitors add forecasting but need a pane you will eventually stop looking at.
  • The status line runs locally and costs no tokens, but it must be fast.

The four approaches

Terminal monitoring approaches compared.

ApproachSetupAttention costShows
Your own status lineOne config line and a scriptZero, it is in the promptLive quota, context, cost, anything
ccusage statuslineOne config lineZero, it is in the promptSession and daily spend, block, burn rate
Claude Code Usage MonitorAn installA dedicated paneQuota, burn rate, forecasting, exports
ccusage blocks --activeNoneA dedicated paneConsumption in the current window

The zero-code option

If you want a useful readout in under a minute, use the one ccusage ships.

~/.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "bunx ccusage statusline",
    "padding": 0
  }
}

You get the active model and effort level, session cost, today's total, the current 5-hour block cost with time remaining, burn rate per hour, and context usage. It runs offline against a cached pricing snapshot by default, which is what keeps it fast enough to render on every message. Useful flags are --visual-burn-rate for an at-a-glance indicator and --cost-source to choose whose cost calculation you trust.

Write your own status line

Claude Code runs your command and pipes a JSON blob of session state to it on stdin. Your script prints text, Claude Code renders it. Every field you might want is in that blob, including the plan percentages that nothing else local can see.

The fields worth reading, from the documented schema.

FieldContains
rate_limits.five_hour.used_percentagePercent of the 5-hour window consumed, 0 to 100
rate_limits.seven_day.used_percentageThe same for the weekly window
rate_limits.*.resets_atUnix epoch seconds when that window resets
context_window.used_percentageHow full this conversation is
cost.total_cost_usdSession cost, computed locally at list rates
model.display_name, effort.levelWhat is running, and at what effort
workspace.git_worktree, pr.numberWhich worktree, and any open PR for the branch
~/.claude/statusline.sh, then chmod +x it. Two rows: context above, quota below.
#!/usr/bin/env bash
# Two lines: context on top, plan quota below. Each printf is one row.
input=$(cat)
dir=$( jq -r '.workspace.current_dir'                       <<< "$input")
model=$(jq -r '.model.display_name'                          <<< "$input")
h5=$(  jq -r '.rate_limits.five_hour.used_percentage // 0'   <<< "$input")
d7=$(  jq -r '.rate_limits.seven_day.used_percentage // 0'   <<< "$input")
ctx=$( jq -r '.context_window.used_percentage // 0'          <<< "$input")
branch=$(git -C "$dir" branch --show-current 2>/dev/null)

bar() {                                   # bar <percent> <width>
  local n=$(( ${1%%.*} * $2 / 100 ))
  printf '%*s' "$n"        '' | tr ' ' '#'
  printf '%*s' "$(( $2 - n ))" '' | tr ' ' '.'
}
hue() { [ "${1%%.*}" -ge 80 ] && printf '\033[31m' || printf '\033[32m'; }

printf '%s  %s  ctx %.0f%%\n' "$model" "${branch:-no branch}" "$ctx"
printf '%b5h [%s] %.0f%%   7d [%s] %.0f%%\033[0m\n' \
  "$(hue "$h5")" "$(bar "$h5" 12)" "$h5" "$(bar "$d7" 12)" "$d7"
~/.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2,
    "refreshInterval": 30
  }
}

The rules that make a status line good

  • Each printed line is a row. Two printf calls give you two rows, which is how you fit a bar and a label without crowding.
  • Keep it fast. The script runs on session start, on every new assistant message, after /compact, and on permission or vim mode changes, debounced at 300ms. A slow script is a visibly stuttering prompt.
  • Cache anything expensive. Shelling out to npx per render is the classic mistake. Write the figure to a file from a background job and have the status line read the file.
  • Set refreshInterval for time-based segments. Event triggers go quiet while a coordinator waits on background subagents, so a countdown freezes without it. The minimum is 1 second.
  • Read COLUMNS, not tput cols. Claude Code captures the output rather than attaching your script to the terminal, so width detection from inside the script fails. It sets COLUMNS and LINES for you.
  • Colour and links work. ANSI escapes render, and OSC 8 hyperlinks are clickable in terminals that support them, such as iTerm2, Kitty, and WezTerm.

The caching rule deserves a worked example, because it is the difference between a status line that feels native and one that stutters. Anything that spawns a process per render is too slow. Compute it out of band and read a file:

A background refresher, run from cron or a launch agent every five minutes.
npx ccusage@latest daily --json --offline \
  | jq -r '.daily[-1].totalCost // 0' \
  > "$HOME/.claude/today-cost.txt"
The status line then costs one read.
today=$(cat "$HOME/.claude/today-cost.txt" 2>/dev/null || echo 0)
printf ' | $%.2f today' "$today"

When you want a full pane

If you want forecasting and exports rather than a single line, the community TUI is the mature option.

Claude Code Usage Monitor.
# install
uv tool install claude-monitor

# run
claude-monitor

Its 4.0 release moved to the official status line rate_limits as its primary data source rather than inferring limits from token counts, added machine-readable JSON, CSV, and text output, and added an opt-in local usage warehouse so history survives past the 30-day transcript sweep. It also plots a burn rate and predicts when the window closes.

The no-install alternative, in a spare split.
npx ccusage@latest blocks --active

What terminal tools cannot do

  • Follow you away from the desk. A long autonomous run finishing while you are elsewhere is exactly when a notification would help.
  • Cover several accounts. A status line describes the session it is rendering, and most parsers read one local directory.
  • Cover several machines. The transcripts are local, so a laptop and a desktop each see half the picture of one shared allowance.
  • Survive the sweep. Claude Code deletes transcripts after cleanupPeriodDays, 30 days by default, so a CLI parser cannot show you a quarter.
  • Bucket by repository. Grouping is by project directory, so git worktrees fragment one repo into several rows.

Questions people ask

For zero effort, bunx ccusage statusline. For remaining plan quota, a status line script that reads the rate_limits fields. For forecasting and exports in a dedicated pane, Claude Code Usage Monitor.

Yes. Set statusLine to a command in ~/.claude/settings.json. Claude Code pipes session state to it as JSON on stdin, including rate_limits percentages and reset times, and renders whatever your script prints.

They can now. Anything that reads the status line JSON gets rate_limits.five_hour and rate_limits.seven_day directly. Tools that only parse the JSONL session files cannot, because that state is never written to disk.

It can. The command runs on every render, debounced at 300ms, and an in-flight script is cancelled if a new update triggers. Keep it to jq over stdin and a cached file rather than a network call or an npx spawn.

Print more than one line. Each echo or printf statement renders as a separate row, so you can put git and model on one row and a quota bar on the next.

Because Claude Code captures your script's output instead of attaching it to the terminal, so tput cols and language-level width detection fail. Read the COLUMNS and LINES environment variables, which Claude Code sets before running your script.

ccusage reads fifteen agent CLIs including Codex, so its reports do. A Claude Code status line does not, because it only ever describes the Claude Code session rendering it. Cross-agent live monitoring needs a separate app.

Removed in v18.0.0. Use blocks --active for the current window with projections, or the ccusage statusline command for continuous display in your prompt.

Sources

Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.

  1. Claude Code: customize your status line
  2. Claude Code settings reference
  3. ccusage on GitHub
  4. ccusage documentation
Try it

Ambient, not
another pane.

Continuum puts live quota in the menu bar and on your phone, so monitoring costs no screen space and no attention.

free app · your subscriptions · local-first