Progress bars for the session (5h) and week (7d) rate limits in the prompt footer

A Claude Code mod that shows your session (5-hour) and week (7-day) rate-limit usage as progress bars in the prompt footer.
Session ████░░░░░░ 42% · Week █░░░░░░░░░ 7%
The bars appear next to the session mode indicator and update whenever Claude Code re-measures your rate limits.
From inside Claude Code:
/plugin marketplace add Abdallah-Abdelazim/usage-limits-cc-mod
/plugin install usage-limits@usage-limits-local
Then reload plugins (or restart the session).
The mod is a plugin of function hooks (hooks/hooks.json → hooks/register.ts):
| Hook | What it does |
|---|---|
session.start | Reads current usage via $.session.usage() and stores the formatted line. |
session.measure | Refreshes the line when rateLimits changed. |
ui.render (SessionMode) | Appends the line to the session mode indicators. |
hooks/format.ts renders each limit as a 10-cell bar (█ filled, ░ empty), clamped to 0–100%. Only the five_hour (Session) and seven_day (Week) limits are shown; other kinds are ignored. If no limits are reported, nothing is rendered.
hooks/
hooks.json module manifest
register.ts hook registration
format.ts bar / line formatting
format.test.ts tests (claude-code/testing)
types/index.d.ts plugin state typings
Tests use the claude-code/testing harness provided by Claude Code.
hooks/register.ts 28 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4import { line } from './format'
5
6const text = atom({ plugin: 'usage-limits', key: 'text' } as const, null)
7
8export const register: Register = on => {
9 on('session.start', async ($, e, next) => {
10 const latest = line((await $.session.usage()).rateLimits) ?? null
11 await update($, text, () => latest)
12
13 return next(e)
14 })
15
16 on('session.measure', async ($, e, next) => {
17 if (e.changed.includes('rateLimits')) await update($, text, () => line(e.rateLimits) ?? null)
18
19 return next(e)
20 })
21
22 on('ui.render', { component: 'SessionMode' }, async ($, e, next) => {
23 const current = await read($, text)
24
25 return next(current ? { ...e, props: { ...e.props, modes: [...e.props.modes, current] } } : e)
26 })
27}
28hooks/format.ts 19 lines1import type { SessionRateLimit } from 'claude-code'
2
3const WIDTH = 10
4const LABELS: Record<string, string> = { five_hour: 'Session', seven_day: 'Week' }
5
6export const bar = (percent: number): string => {
7 const filled = Math.round((Math.min(Math.max(percent, 0), 100) / 100) * WIDTH)
8
9 return '█'.repeat(filled) + '░'.repeat(WIDTH - filled)
10}
11
12export const line = (limits: readonly SessionRateLimit[]): string | undefined => {
13 const parts = limits
14 .filter(l => l.kind in LABELS)
15 .map(l => `${LABELS[l.kind]} ${bar(l.percentUsed)} ${Math.round(l.percentUsed)}%`)
16
17 return parts.length ? parts.join(' · ') : undefined
18}
19types/index.d.ts 6 lines1declare module 'claude-code' {
2 interface PluginState {
3 'usage-limits': { text: string | null }
4 }
5}
6