Pins context window fill, tokens, cost and rate limits above the prompt

Claude Code mod that pins a live usage line under the prompt, updated after every turn:
ctx 84k/200k (42%) · $1.23 · five_hour 18% · seven_day 5%
Context tokens / window, session cost, and rate-limit usage.
/plugin install context-meter --marketplace ezekohon/context-meter
Or point CLAUDE_CODE_PLUGIN_DIRS at a local clone.
claude plugin validate .
claude plugin test .hooks/register.tsx 38 lines1import { atom, read, update } from 'claude-code'
2import type { Register, SessionContextUsage, SessionCost, SessionRateLimit } from 'claude-code'
3
4const line = atom({ plugin: 'context-meter', key: 'line' } as const, null)
5
6const k = (n: number) => (n >= 1000 ? `${Math.round(n / 1000)}k` : `${n}`)
7
8export const format = (u: { context: SessionContextUsage; cost?: SessionCost; rateLimits: SessionRateLimit[] }) => {
9 const { tokens, window, percent } = u.context
10 const parts = [`ctx ${k(tokens ?? 0)}/${k(window)}${percent === undefined ? '' : ` (${Math.round(percent)}%)`}`]
11 if (u.cost) parts.push(`$${u.cost.usd.toFixed(2)}`)
12 for (const r of u.rateLimits) parts.push(`${r.kind} ${Math.round(r.percentUsed)}%`)
13 return parts.join(' · ')
14}
15
16export const register: Register = on => {
17 on('session.start', async ($, e, next) => {
18 const r = await next(e)
19 const text = format(await $.session.usage())
20 await update($, line, () => text)
21 return r
22 })
23
24 on('session.measure', async ($, e, next) => {
25 const text = format(e)
26 await update($, line, () => text)
27 return next(e)
28 })
29
30 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
31 const text = await read($, line)
32 if (e.props.hasSurvey || text === null) return next(e)
33
34 const { Text } = $.ui.resolve(e)
35 return <Text dimColor>{text}</Text>
36 })
37}
38types/index.d.ts 8 lines1export type Line = string | null
2
3declare module 'claude-code' {
4 interface PluginState {
5 'context-meter': { line: Line }
6 }
7}
8