SLOPSHOPPER

context-status

Shows the context window fill and the 5-hour and weekly usage limits, as a status line under the prompt.

newstatus
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · context-status
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts ⚠ context-status: Context █████░░░░░ 49% · 97k/200k · 51% left │ 5h 31%
README

context-status

A Claude Code mod that keeps a status line under the prompt with how full the context window is and how much of your usage limits you have used.

Context █████░░░░░ 45% · 90k/200k · 55% left │ 5h 34% (resets 2h10m) · Week 82.5% ! (resets 3d4h)
PartMeaning
Context … 45%Tokens the last reply was answered over, against the model's context window. (compact soon) shows at 80 % or more.
5h 34%Use of the 5-hour usage window.
Week 82.5%Use of the 7-day usage window. ! shows at 80 % or more.
Spend …A gateway spend limit, when your account has one.
(resets …)Time left until that window starts again.

The line updates after each turn, and when a usage window moves by a whole percent. The usage windows show only on a Claude subscription (Pro or Max), after the first reply of a session; with an API key only the context part shows. The mod sends nothing anywhere: it reads the same figures as Claude Code's own status line.

Install

At the prompt of a Claude Code terminal session:

/plugin install context-status --marketplace anchorsprint/claude-mods

From a shell:

claude plugin install context-status --marketplace anchorsprint/claude-mods

Develop

claude plugin validate plugins/context-status
claude plugin test plugins/context-status
claude --plugin-dir plugins/context-status
Source 1 files
hooks/register.ts 60 lines
1import type { Register, SessionContextUsage, SessionRateLimit } from 'claude-code'
2
3const BAR_CELLS = 10
4const LIMIT_LABELS: Record<string, string> = { five_hour: '5h', seven_day: 'Week', spend_limit: 'Spend' }
5
6const compact = (n: number) =>
7  n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : `${Math.round(n / 1000)}k`
8
9const bar = (percent: number) => {
10  const filled = Math.max(0, Math.min(BAR_CELLS, Math.round((percent / 100) * BAR_CELLS)))
11  return '█'.repeat(filled) + '░'.repeat(BAR_CELLS - filled)
12}
13
14export const resetsIn = (resetsAt: string | undefined, now: number) => {
15  const at = resetsAt === undefined ? NaN : Date.parse(resetsAt)
16  if (Number.isNaN(at)) return ''
17  const minutes = Math.max(0, Math.round((at - now) / 60_000))
18  const days = Math.floor(minutes / 1440)
19  const hours = Math.floor((minutes % 1440) / 60)
20  const left = days > 0 ? `${days}d${hours}h` : hours > 0 ? `${hours}h${minutes % 60}m` : `${minutes}m`
21  return ` (resets ${left})`
22}
23
24export const contextText = (context: SessionContextUsage) => {
25  const window = compact(context.window)
26  if (context.tokens === undefined || context.percent === undefined) {
27    return `Context: no reading yet (${window} window)`
28  }
29  const left = Math.max(0, 100 - context.percent)
30  const warn = context.percent >= 80 ? ' (compact soon)' : ''
31  return `Context ${bar(context.percent)} ${context.percent}% · ${compact(context.tokens)}/${window} · ${left}% left${warn}`
32}
33
34export const limitText = (limit: SessionRateLimit, now: number) => {
35  const label = LIMIT_LABELS[limit.kind] ?? limit.kind
36  const warn = limit.percentUsed >= 80 ? ' !' : ''
37  return `${label} ${limit.percentUsed}%${warn}${resetsIn(limit.resetsAt, now)}`
38}
39
40export const statusText = (context: SessionContextUsage, rateLimits: readonly SessionRateLimit[], now: number) =>
41  [contextText(context), rateLimits.map(limit => limitText(limit, now)).join(' · ')]
42    .filter(part => part !== '')
43    .join(' │ ')
44
45export const register: Register = on => {
46  on('session.start', async ($, e, next) => {
47    const started = await next(e)
48    const { context, rateLimits } = await $.session.usage()
49    $.ui.status(statusText(context, rateLimits, await $.clock.now()))
50    return started
51  })
52
53  on('session.measure', async ($, e, next) => {
54    if (e.changed.includes('context') || e.changed.includes('rateLimits')) {
55      $.ui.status(statusText(e.context, e.rateLimits, await $.clock.now()))
56    }
57    return next(e)
58  })
59}
60