Claude Code status line: 5-hour limit, weekly limit and context window, with colored dots and time to reset.

A Claude Code mod (plugin) that shows your usage limits and context window in the status line at the bottom of the window:
5h 🟢 17% 3h 12m | 7d 🟠 82% 3d 22h | CTX 🟢 70k/200k
| Part | Meaning |
|---|---|
5h 🟢 17% 3h 12m | 5-hour limit usage and time until it resets |
7d 🟠 82% 3d 22h | weekly limit usage and time until it resets |
CTX 🟢 70k/200k | tokens used in the context window / window size |
The dot shows how close you are to the limit:
| Dot | Usage |
|---|---|
| 🟢 | below 50% |
| 🟡 | 50% and up |
| 🟠 | 75% and up |
| 🔴 | 90% and up |
| ⚪ | no data yet (e.g. before the first reply, or no subscription) |
The line refreshes after every Claude reply. It works in the terminal and in the Code tab of the Claude desktop app.
In a Claude Code terminal session:
/plugin install 5h --marketplace emilmaju/claude-statusline-mod
Confirm adding the marketplace (y) and pick the user scope so the mod runs in every project.
Or from the command line:
claude plugin marketplace add emilmaju/claude-statusline-mod
claude plugin install 5h@emilmaju --scope user
The status line appears on its own from the next session, in the desktop app too.
claude plugin marketplace update emilmaju
claude plugin uninstall 5h
Claude Code puts the name of the plugin in front of its status line entry, and that can't be turned off. So the plugin is named 5h: the name doubles as the label of the first limit, and the mod's own text starts right at the dot.
The whole mod is one file, hooks/register.ts. It uses two events from the Claude Code mod API:
session.start: the first reading from $.session.usage() when a session starts,session.measure: later readings, whenever the context or a limit changes,and sets the text with $.ui.status(...). It doesn't read files, touch the network or run processes.
claude plugin validate .
claude plugin test .
To run the mod from a local folder without installing it:
claude --plugin-dir .
hooks/register.ts 60 lines1import type { Register } from 'claude-code'
2
3type Limit = { kind: string; percentUsed: number; resetsAt?: string }
4type Context = { percent?: number; tokens?: number; window: number }
5
6// Kolor kropki według zużycia: zielony → żółty → pomarańczowy → czerwony.
7const dot = (percent: number | null | undefined) => {
8 if (percent === null || percent === undefined) return '⚪'
9 if (percent >= 90) return '🔴'
10 if (percent >= 75) return '🟠'
11 if (percent >= 50) return '🟡'
12 return '🟢'
13}
14
15const pct = (percent: number) => `${Math.round(percent)}%`
16
17const timeLeft = (iso: string | undefined, now: number) => {
18 if (!iso) return ''
19 const min = Math.round((Date.parse(iso) - now) / 60000)
20 if (!(min > 0)) return ''
21 if (min >= 24 * 60) return `${Math.floor(min / 1440)}d ${Math.floor((min % 1440) / 60)}h`
22 if (min >= 60) return `${Math.floor(min / 60)}h ${min % 60}m`
23 return `${min}m`
24}
25
26const tokens = (n: number) =>
27 n >= 1_000_000 ? `${+(n / 1_000_000).toFixed(1)}M` : n >= 1000 ? `${Math.round(n / 1000)}k` : `${n}`
28
29// Desktop dokleja przed wpisem nazwę moda („5h”), więc linia zaczyna się
30// od razu od kropki limitu 5h i daje: 5h 🟢 17% 3h 12m | 7d … | CTX …
31export const line = (limits: readonly Limit[], context: Context, now: number) => {
32 const limit = (kind: string, label: string) => {
33 const l = limits.find(x => x.kind === kind)
34 if (!l) return `${label}${dot(null)} –`
35 const left = timeLeft(l.resetsAt, now)
36 return `${label}${dot(l.percentUsed)} ${pct(l.percentUsed)}${left ? ` ${left}` : ''}`
37 }
38 const ctx =
39 context.tokens !== undefined && context.window
40 ? `CTX ${dot(context.percent)} ${tokens(context.tokens)}/${tokens(context.window)}`
41 : `CTX ${dot(null)} –`
42
43 return `${limit('five_hour', '')} | ${limit('seven_day', '7d ')} | ${ctx}`
44}
45
46export const register: Register = on => {
47 on('session.start', async ($, e, next) => {
48 const usage = await $.session.usage()
49 $.ui.status(line(usage.rateLimits, usage.context, await $.clock.now()))
50
51 return next(e)
52 })
53
54 on('session.measure', async ($, e, next) => {
55 $.ui.status(line(e.rateLimits, e.context, await $.clock.now()))
56
57 return next(e)
58 })
59}
60