A Claude Code status line that shows weekly remaining
August 25, 2026
A Claude Code status line can print weekly remaining from JSON that is already on stdin. /statusline can write a working script today if you name those fields. One inspectable jq process is still the version you can mock-test.
The default chrome waits until you are almost out. A March 2026 r/claude thread already noticed the limits ride stdin and still stay off the bar.
/usage is a command you remember to run. The row under the prompt is the only place remaining can sit while a turn is in flight.
What has to be true first#
Claude Code's status line docs send session JSON to whatever command you configure. The process is local. It does not spend API tokens, and it does not call Claude.
Pin the CLI first.
- Claude Code 2.1.243 or newer, so
modelPricingexists andrate_limitsno longer sticks at the pre-reset percent after an idle window jqonPATH. Official examples assume it. This machine did not have it.echo '{}' | jq .has to print{}before later checkpoints mean anything- A Claude.ai Pro or Max login for the weekly numbers.
rate_limitsis absent on API-key sessions, and it is absent on Pro and Max until the first API response
COLUMNS and LINES are set for the script as of 2.1.153. GitHub pr.number and pr.url land in 2.1.234. Neither is required to print remaining, so leave them out of the first command and keep the bar short.
If the week is the thing you are trying not to blow, a routine still draws down the same cap. This post is the bar. That one is the drain.
Wire remaining into the bar#

The field is not called remaining. Context-window JSON has remaining_percentage. Rate-limit JSON does not.
You get used_percentage from 0 to 100 on five_hour and seven_day, plus resets_at as Unix epoch seconds. Remaining is the unread side of the same meter, 100 minus used.
That invert is the post. Everything else is wiring.
1. Keep the command inspectable#
/statusline show weekly remaining will generate a working script into ~/.claude/ and patch settings for you. That path is real. Use it if you want Claude to write the file.
Own the command anyway.
The generated file is a snapshot of the fields you named in that sentence, same as this jq is a snapshot of the fields it reads. Neither grows when later JSON lands. COLUMNS, PR badges, and modelPricing showed up in later releases. You add them by editing the command, not by hoping a generated file mutates.
The win is a 12-line script you can pipe mock JSON through. Two minutes. No extra Claude call per render.
2. Invert used into remaining with one jq#
Save this as ~/.claude/statusline-remaining.sh. exec hands stdin straight to jq, so there is no extra Claude call and no second process chewing git.
#!/usr/bin/env bash
exec jq -r '[
.model.display_name,
((.rate_limits.five_hour.used_percentage) | if . == null then empty else "5h left \(100 - (. | round))%" end),
((.rate_limits.seven_day.used_percentage) | if . == null then empty else "7d left \(100 - (. | round))%" end)
] | join(" · ")'empty inside a jq array drops the slot. Before the first reply, the row is just the model name. After it, you get Sonnet · 5h left 76% · 7d left 59% on the sample payload from the docs (used 23.5 and 41.2).
Make it executable.
chmod +x ~/.claude/statusline-remaining.shPipe a mock. If this prints the two LEFT percents, the live bar will too.
echo '{"model":{"display_name":"Sonnet"},"rate_limits":{"five_hour":{"used_percentage":23.5},"seven_day":{"used_percentage":41.2}}}' | ~/.claude/statusline-remaining.shExpect Sonnet · 5h left 76% · 7d left 59%. Round used, then subtract. Do not invent a remaining field.
3. Point settings.json at that command#
Put this in ~/.claude/settings.json. User scope, not the project file. The bar is yours on every repo.
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline-remaining.sh"
}
}Leave refreshInterval unset. Remaining percent does not tick on its own. A one-second refresh is how people hitch the prompt with git or bun.
Claude Code already re-runs the command when a new assistant message arrives, when /compact finishes, and when permission mode changes. Debounce is 300 ms. A new update cancels a script that is still running.
Settings reload on save. No restart.
4. Send one prompt and read the bar#
Send something cheap. ping is enough.
After the first API response, the row under the prompt should show 5h left and 7d left. If it still shows only the model, you are on an API key, or the first response has not landed, or jq exited non-zero and blanked the row.
claude --debug is the next move. A skipped command logs Status line command skipped: workspace trust not accepted. Accept the trust dialog and restart once.
/cost is an alias of /usage in the commands reference. Run it once and check the plan bars against the new line. The percents should agree. The status line inverts them, /usage prints used.
5. Point org /cost at contracted rates#
Skip this on Pro and Max. Session dollars on /usage are not the plan bill. Claude Code's cost page says that figure is for API users, computed from list rates.
On an org API seat, list rate is the lie you have been reading. The 2.1.243 changelog added a managed modelPricing setting so contracted per-model rates and a discount multiplier feed /cost, the status line's cost.total_cost_usd, and telemetry instead of list price.
You do not paste that key into ~/.claude/settings.json. An admin deploys it in managed settings. The public schema still lags the changelog, so do not invent a JSON shape. After it lands, /cost and the bar should stop quoting the public card.
The remaining invert does not wait on that key. Weekly left is a percent of the window, not a dollar.
When it breaks#

The bar will look like a bug the first afternoon. It is usually one of four.
- Esc hint gone. A custom status line sits in its own row above the footer badges and does not replace them. Claude Code then hides most footer keyboard hints, including
esc to interrupt. Esc still interrupts. The hint is what you lost. - Prompt hitches. The script runs often.
git statusin a cold repo, a bun renderer, or a curl to the OAuth usage API will block the bar until they finish. A newer update cancels the in-flight run, so you get stale text or a blank. Stay on onejq. No network. No git. - Row is blank. Non-zero exit, missing
jq, script not executable,disableAllHookstrue, orgallowManagedHooksOnlywith no managedstatusLine, or trust not accepted. Replay the mock from step 2. - API-key sessions. Docs limit
rate_limitsto Claude.ai Pro and Max after the first response. The support article that still says watch remaining with/statusis not the stdin contract.
Do not set refreshInterval to 1 until you actually want a clock. Remaining percent does not need a timer. A heavy command on that tick hitches every turn.
During a long tool turn the activity line can overwrite the custom row. That is a known hole, not your script. The numbers come back when the turn ends.
What now sits under the prompt#
On Pro and Max the proof is the bar after the first reply, 5h left and 7d left, matching /usage inverted. On an org API seat the percents never appear. modelPricing is a separate cost-display problem, and it does not mint weekly remaining.
If the mock from step 2 already printed Sonnet · 5h left 76% · 7d left 59%, the feature is the command. Claude is not in the loop.
Status line remaining, asked for real
Why isn't remaining already on the default bar?
Claude Code already receives rate_limits on stdin for Pro and Max after the first API response. The default chrome does not print it. The field is consumed percent, so remaining is 100 minus that number in your command.
Can /statusline just write this for me?
/statusline takes a sentence and writes a script in ~/.claude/. That can work today if you name remaining. The file is still a snapshot of the fields you asked for, same as a hand-written jq. Own the command when you want a mock-testable invert without another Claude call.
Why is the bar blank until the first reply?
rate_limits is absent until the first API response in the session, and only for Claude.ai Pro or Max. An API-key session never gets the object. Handle absence with // empty so the row still prints the model.
Where did esc to interrupt go?
A custom status line sits above the footer badges and does not replace them. Claude Code then hides most footer keyboard hints, including esc to interrupt. Esc still interrupts. The hint is just gone.
Why does /cost still look like list price?
/cost is an alias of /usage. The dollar figure is computed client-side from list rates unless your org deploys the modelPricing managed setting added in 2.1.243. Pro and Max session dollars are not the plan bill. Remaining on rate_limits is the bar that matters there.
