DEV Community

Cover image for Keep your Claude Code cost, usage, and context info always visible
Ricardo Martin
Ricardo Martin

Posted on Originally published at ricmart.in

Keep your Claude Code cost, usage, and context info always visible

As LLMs become better and our AI usage grows, managing token usage as well as model's context window has become increasingly important.

Three months ago, I switched to Claude Code from Cursor, and I quickly started to miss having that information always visible. A few weeks in, I found myself constantly hitting the /usage command to check how the session was performing in terms of cost, token input/output and overall context window status.

I was wondering: If all that data already exists, I should be able to bring it wherever I want and see it change in real time. And it turns out it is not only possible but also quite easy to do.

The key component we're looking for is the status line. That thin row under your prompt can become a small dashboard, tailored to exactly the numbers you care about (and it is highly customizable!). Here is how to set it up, and a few things the docs do not tell you.

What the status line actually is

The status line is not a fixed set of toggles. It is a command you define. Claude Code runs it, pipes a JSON blob describing the current session into it via stdin, and prints whatever your command writes to stdout.

That is the mental model, and this is the important part: if you can compute it in a script, you can show it. Cost, model, branch, context percentage, failing tests, the ticket you are on, etc.

The JSON output looks roughly like this:

{
  "model": { "id": "claude-opus-4-8", "display_name": "Opus" },
  "workspace": { "current_dir": "/Users/you/projects/app" },
  "cost": {
    "total_cost_usd": 0.4213,
    "total_lines_added": 156,
    "total_lines_removed": 23
  },
  "context_window": {
    "used_percentage": 42,
    "total_input_tokens": 99201,
    "total_output_tokens": 1822
  }
}
Enter fullscreen mode Exit fullscreen mode

The fast way: let Claude write it

Claude Code ships a command that configures a status line for you: /statusline. It takes plain-English instructions, so you can be specific — for example, /statusline show the model, git branch, context percentage and session cost.

Claude writes the script, drops it in ~/.claude/, and wires it into your settings. If you just want to get started, you can stop reading here.

The advanced way: creating and configuring your own script

If you're nitpicky like me, the alternative is to write the script yourself, so it shows exactly what you want and nothing else. I run Claude Code inside Warp, which already surfaces things like the working directory and git branch in its own UI, so I deliberately left those out of the status line and kept only the session numbers I can't get anywhere else: the model, cost, context usage, token input/output, and lines changed by the agent in the current session.

#!/usr/bin/env bash
# ~/.claude/statusline.sh
input=$(cat)

model=$(echo "$input"   | jq -r '.model.display_name')
cost=$(echo "$input"    | jq -r '.cost.total_cost_usd // 0')
ctx=$(echo "$input"     | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
in_tok=$(echo "$input"  | jq -r '.context_window.total_input_tokens // 0')
out_tok=$(echo "$input" | jq -r '.context_window.total_output_tokens // 0')
added=$(echo "$input"   | jq -r '.cost.total_lines_added // 0')
removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')

printf "[%s] \$%.4f | ctx %s%% | in %s | out %s | +%s/-%s" \
  "$model" "$cost" "$ctx" "$in_tok" "$out_tok" "$added" "$removed"
Enter fullscreen mode Exit fullscreen mode

Which renders as a single row:

[Opus 4.8 (1M context)] $6.8190 | ctx 10% | in 99201 | out 1822 | +188/-6
Enter fullscreen mode Exit fullscreen mode

A couple of details worth pointing out:

  • The // 0 in each jq filter acts as a fallback. Some fields are null before the first API response of a session (and after a /compact), so without it you would get an empty value printed in those cases.
  • context_window.total_input_tokens and total_output_tokens are the tokens currently in the window (input already includes cache reads and writes), not cumulative session totals — so they track what is actually loaded right now, next to the ctx percentage.

Make it executable:

chmod +x ~/.claude/statusline.sh
Enter fullscreen mode Exit fullscreen mode

And point your settings at it in ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}
Enter fullscreen mode Exit fullscreen mode

Settings reload on their own, but the line only redraws on your next interaction with Claude Code.

My Claude Code status line showing model, cost, context usage, token input/output, and lines changed


This is what mine looks like in a real session

[!TIP]
Test the script before wiring it up, so you don't end up debugging blind inside Claude Code. Pipe it some mock JSON and check the output:

echo '{"model":{"display_name":"Opus"},"cost":{"total_cost_usd":0.42,"total_lines_added":10,"total_lines_removed":2},"context_window":{"used_percentage":42,"total_input_tokens":99201,"total_output_tokens":1822}}' | ~/.claude/statusline.sh
Enter fullscreen mode Exit fullscreen mode

Tips the docs don't explain

A few things I found out after using it for a while:

Watch context, not just cost. Cost is the number we naturally reach for, but context_window.used_percentage is the one that actually changes how you work. Seeing the window fill up tells you when to /compact or start fresh before quality degrades.

Refresh on a timer for anything time-based. Updates are event-driven (after each message, after /compact, and so on), which means they go quiet when the session is idle (e.g. while background subagents churn). Add "refreshInterval": 5 next to your command to also re-run every N seconds and keep a clock or live git state fresh.

On Pro/Max, you can surface rate limits. The JSON carries rate_limits.five_hour and rate_limits.seven_day with a used_percentage each. This is handy if you're using the latest models in xhigh or higher thinking mode.

[!NOTE]
If you prefer not having to maintain the script yourself, there are some community projects out there like ccstatusline that give you a themeable status line with a configuration UI, no bash required. This will get you much fancier results in no time.

Bonus: an overview of your subagents, too

There's a sibling setting for showing some of the information we have in our statusline for each subagent spawned within the same section too: the subagentStatusLine, which lets you reformat every row in the agent panel the way you reformat the main line:

{
  "subagentStatusLine": {
    "type": "command",
    "command": "~/.claude/subagent-statusline.sh"
  }
}
Enter fullscreen mode Exit fullscreen mode

Before wiring it up, two things worth knowing so you don't end up debugging the wrong thing:

  • It styles the in-session agent panel, not the sessions manager. These are two different screens. The full-screen dashboard you reach with claude agents lists your independent sessions across projects, and subagentStatusLine does not touch that one. What it customizes is the panel of subagents that appears right below your prompt when you are inside a session and Claude spawns child agents (through its Task tool). So to see your script run: open a session, spawn some subagents, and watch the rows beneath the prompt.
  • Cost is not one of the fields. Unlike the main status line, the per-agent payload has no cost object at the moment, so you cannot show a dollar figure next to each agent. What you do get per task is id, name, status, model, tokenCount, and contextWindowSize — which is the barely minimum (and to me, more than enough) for a context percentage, arguably the more useful signal for an agent that is still running.

The command runs once per refresh and receives every visible agent at once, as a tasks array on stdin. You answer with one JSON line per row you want to override, in the shape {"id": "…", "content": "…"}. Here is a starting point that shows each agent's name, model, context usage, and status — adapt it to taste:

#!/usr/bin/env bash
# ~/.claude/subagent-statusline.sh
input=$(cat)

# Emit one {id, content} line per agent: name · model · context % · status
echo "$input" | jq -c '
  .tasks[]
  | select(.contextWindowSize and .tokenCount)
  | { id,
      content: "\(.name)  ·  \(.model // "…")  ·  \(((.tokenCount * 100) / .contextWindowSize) | floor)% ctx  ·  \(.status)" }'
Enter fullscreen mode Exit fullscreen mode

Make it executable (chmod +x ~/.claude/subagent-statusline.sh) and it takes over each agent row.

[!NOTE]
The per-agent model and contextWindowSize fields need Claude Code v2.1.205 or later, and are omitted for an agent whose model has not resolved yet. The select(...) above just leaves those rows with their default formatting until it does. Any row whose id you don't return keeps the default name · description · token count, and an empty content hides a row entirely.

A custom subagent status line showing each agent's model and context usage in the in-session subagent panel



Each agent's model and context usage at a glance in the subagent panel below the prompt

Why having this information in real time helps

Even though you have the Max plan, in my opinion it is a good idea to keep track of your context, cost and overall usage for the following reasons:

  • Real-time cost awareness. Watching spend accumulate nudges better decisions about when to open a fresh session or compact context, as well as understanding how you're being charged based on the model and thinking mode you're using. In my case, I was able to get the same results 95% of the times by reducing the cost ~40%, just by playing with the model and thinking mode. Raising awareness of real API cost usage is an increasingly important skill to develop, to be ready for when the party is over.
  • Knowing when to reset the context. Cost tells you what a session has spent; the context percentage tells you when it's about to get worse. It has been demonstrated that model quality degrades as the window fills up, as agents tend to reduce thinking cycles if they know the remaining context is small, so watching ctx climb is my clue to /compact or start fresh before the answers start slipping, instead of noticing after it.
  • Catching a runaway session early. When the token or cost counters climb faster than the requested task complexity suggests, that's usually a sign something is off: an agent stuck in a loop, re-reading huge files, or running a heavier thinking mode than it needs. Having the numbers in front of me means I catch it fast and I can step in.

Go deeper

To deep dive on this feature; every JSON field, the /statusline command, padding, multi-line output, colors, and clickable links, visit the official docs: code.claude.com/docs/en/statusline

Top comments (0)