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.
- A status line command puts live quota in your prompt at zero attention cost.
- Claude Code pipes
rate_limits.five_hourandseven_dayto that command on stdin. bunx ccusage statuslineis 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.
| Approach | Setup | Attention cost | Shows |
|---|---|---|---|
| Your own status line | One config line and a script | Zero, it is in the prompt | Live quota, context, cost, anything |
ccusage statusline | One config line | Zero, it is in the prompt | Session and daily spend, block, burn rate |
| Claude Code Usage Monitor | An install | A dedicated pane | Quota, burn rate, forecasting, exports |
ccusage blocks --active | None | A dedicated pane | Consumption in the current window |
The zero-code option
If you want a useful readout in under a minute, use the one ccusage ships.
{
"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.
| Field | Contains |
|---|---|
rate_limits.five_hour.used_percentage | Percent of the 5-hour window consumed, 0 to 100 |
rate_limits.seven_day.used_percentage | The same for the weekly window |
rate_limits.*.resets_at | Unix epoch seconds when that window resets |
context_window.used_percentage | How full this conversation is |
cost.total_cost_usd | Session cost, computed locally at list rates |
model.display_name, effort.level | What is running, and at what effort |
workspace.git_worktree, pr.number | Which worktree, and any open PR for the branch |
#!/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"
{
"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
printfcalls 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
npxper render is the classic mistake. Write the figure to a file from a background job and have the status line read the file. - Set
refreshIntervalfor 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, nottput cols. Claude Code captures the output rather than attaching your script to the terminal, so width detection from inside the script fails. It setsCOLUMNSandLINESfor 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:
npx ccusage@latest daily --json --offline \
| jq -r '.daily[-1].totalCost // 0' \
> "$HOME/.claude/today-cost.txt"
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.
# 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.
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.