One line in Node: model, project, branch, the time of the last token change (to judge prompt-cache expiry), a context bar measured against the usable window, and five-hour and seven-day usage with reset countdowns. No network calls. Overwrites one small state file in the system temp folder on each render.
0 copies
Preview
◆ Opus 4.8 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ██▄░░░░░░░ 26% (44K/167K) │ 26% ↻2h6m │ 7% ⟳2d0h◆ Opus 4.8 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ░░░░░░░░░░ 0% (0K/167K)◆ Sonnet 4.6 │ ▪ app │ ⎇ feat/auth │ ◷ 14:04 │ █████▄░░░░ 57% (96K/167K) │ 40% ↻1h11m │ 18% ⟳2d21h◆ Opus 4.8 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ██████████ 100% (182K/167K) │ 88% ↻17m │ 61% ⟳19h59m◆ Fable 5 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ██████▄░░░ 66% (640K/967K) │ 33% ↻3h29m │ 80% ⟳4d23h◆ Haiku 4.5 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ░░░░░░░░░░ 0% (0K/167K) │ 52% ↻4h1m◆ Opus 4.8 │ ▪ feature │ ⎇ worktree-feature │ ◷ 14:04 │ ████▄░░░░░ 44% (74K/167K) │ 44% ↻2h49m │ 20% ⟳1d6h◆ Opus 4.8 │ ▪ scratch │ ◷ 14:04 │ ██▄░░░░░░░ 26% (44K/167K)What it does
One line with model, project, git branch, the clock time your token count last changed, a context bar, and five-hour and seven-day usage with reset countdowns.
- Written in
- Node.js
- Network access
- None
- Works in
- Terminal
How it works
- Reads model, cwd, context use and rate limits, then runs git branch --show-current.
- Measures context against the window minus 33,000 tokens, so 200K shows as 167K.
- The ◷ time stays put until the token count moves, using a saved copy of the last count.
- Turns the bar yellow at 60K tokens and orange at 80K, whatever the window size.
Good to know
- Overwrites claude-status-line-state.json in the OS temp folder on every render and never removes it.
- That one file is shared by all sessions, so two open sessions keep resetting each other's clock.
- Near a full window the bar pins at 100% and the count can pass the window, as in 182K/167K.
Source
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const os = require('os');
const { execSync } = require('child_process');
const STATE_FILE = path.join(os.tmpdir(), 'claude-status-line-state.json');
const AUTOCOMPACT_BUFFER_TOKENS = 33_000;
const WARN_TOKENS = 60_000;
const COMPACT_TOKENS = 80_000;
const RST = '\x1b[0m';
const DIM = '\x1b[38;5;238m';
const MUTED = '\x1b[38;5;245m';
function formatDuration(epoch) {
if (!epoch) return '';
const diff = Math.max(0, Math.round(epoch - Date.now() / 1000));
if (diff <= 0) return 'now';
if (diff < 60) return '<1m';
const d = Math.floor(diff / 86400);
const h = Math.floor((diff % 86400) / 3600);
const m = Math.floor((diff % 3600) / 60);
if (d > 0) return `${d}d${h}h`;
return h > 0 ? `${h}h${m}m` : `${m}m`;
}
function rateLimitColor(pct) {
return pct > 80 ? '\x1b[31m' : pct > 50 ? '\x1b[33m' : '\x1b[32m';
}
function formatRateLimit(rl, icon) {
if (rl?.used_percentage == null) return '';
const pct = Math.round(rl.used_percentage);
const reset = formatDuration(rl.resets_at);
let part = ` │ ${rateLimitColor(pct)}${pct}%${RST}`;
if (reset) part += ` ${MUTED}${icon}${reset}${RST}`;
return part;
}
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => { input += chunk; });
process.stdin.on('end', () => {
try {
const data = JSON.parse(input);
const ctx = data.context_window || {};
const model = data.model || {};
const cwd = data.cwd || '';
const windowSize = ctx.context_window_size ?? 200000;
const effectiveWindow = windowSize - AUTOCOMPACT_BUFFER_TOKENS;
const rawUsedPct = ctx.used_percentage ?? 0;
const tokensUsed = Math.round((rawUsedPct / 100) * windowSize);
const usedPct = Math.min(100, Math.round((tokensUsed / effectiveWindow) * 100));
const level = tokensUsed >= COMPACT_TOKENS ? 'danger' : tokensUsed >= WARN_TOKENS ? 'warn' : 'ok';
const color = level === 'danger' ? '\x1b[38;5;208m' : level === 'warn' ? '\x1b[33m' : '\x1b[32m';
const project = cwd ? path.basename(cwd) : '';
let branch = '';
if (cwd) {
try {
branch = execSync('git --no-optional-locks branch --show-current',
{ cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim().slice(0, 30);
} catch { /* not a git repo */ }
}
const bar = Array.from({ length: 10 }, (_, i) => {
const filled = usedPct - i * 10;
const char = filled >= 8 ? '█' : filled >= 3 ? '▄' : null;
return char ? `${color}${char}${RST}` : `${DIM}░${RST}`;
}).join('');
let lastCallMs;
try {
const prev = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
lastCallMs = prev.tokensUsed === tokensUsed ? prev.timestamp : Date.now();
} catch { lastCallMs = Date.now(); }
fs.writeFileSync(STATE_FILE, JSON.stringify({ tokensUsed, timestamp: lastCallMs }));
const last = new Date(lastCallMs);
const time = `${String(last.getHours()).padStart(2, '0')}:${String(last.getMinutes()).padStart(2, '0')}`;
const tokensK = (tokensUsed / 1000).toFixed(0);
const windowK = (effectiveWindow / 1000).toFixed(0);
let output = `◆ ${(model.display_name ?? 'Claude').replace(/\(1M context\)/, '1M').trim()}`;
if (project) output += ` │ ▪ ${project}`;
if (branch) output += ` │ ⎇ ${branch}`;
output += ` │ ◷ ${time}`;
output += ` │ ${bar} ${usedPct}% (${tokensK}K/${windowK}K)`;
const rateLimits = data.rate_limits || {};
output += formatRateLimit(rateLimits.five_hour, '↻');
output += formatRateLimit(rateLimits.seven_day, '⟳');
process.stdout.write(output);
} catch {
process.stdout.write('Ctx: --');
}
});
More status lines
Color-Coded Context
43 copies
◆ Opus 4.8 │ ▪ app │ ⎇ main │ ◷ 14:04 │ ██▄░░░░░░░ 26% (44K/167K) │ 26% ↻2h6m │ 7% ⟳2d0hGit Detective
13 copies
Op 4.8 │ app (main) │ █░░░░ 44k/200k │ cache 5% ↓2k +5k │ 5h:26%(2h7m) │ 7d:7%(2d)Middle-Dot Ledger
0 copies
Opus 4.8 · high · app (main) · ctx 44k · 5h 26% · 7d 7% · $0.41
Framed Pill Row
0 copies
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ▐ Opus 4.8 ▌ ▐ high ▌ ▐ …/user/app ▌ ▐ main ▌ ▐ 22% / 200k ━━━━━━━━━━ ▌ ▐ 26% ━━━━━━━━━━ 16:10 ▌ ▐ +128 −34 ▌ ▐ $0.41 ▌ ▐ 10m 12s ▌ │
│ MODEL EFFORT PATH BRANCH CONTEXT USAGE DIFF COST TIME │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Single-line usage
140 copies
app · main · Opus-4.8 · effort high · ctx 22% · 5h 26% ↻2h6m · 7d 7% ↻2d0hPace Dot Meters
94 copies
Opus 4.8 [high] ~/app main
16:20:55 | ⛁ ██░░░░░░░░ 22% | 5h ●◔○○○ 26% ↻2h7m | 7d ◔○○○○○○ 7% ↻2d1h │ $0.41 ⏱ 10m
Related mods
Terminal
❯ Run the tests again
● The repo is clean and the tests pass.
✻ Cooked for 0s · done 10:12 PM
☀ 44k │ 5h 26% │ 7d 7% │ cache 5% [-]
❯ Claude Desktop

One line above the prompt: context tokens with their weather, a bar per recent prompt, your 5-hour and 7-day limits against the time elapsed, the prompt cache with its time left, the session cost with the last prompt's share in dollars and in points of the 5-hour limit, and the subagents running. Labels in English, French or Russian. After Token Weather (Anthropic, Apache-2.0) and the ideas of usage-meter (HolyGrail) and prompt-cache-control (Daniel San).
Terminal
❯ /deck demo
⎿ deck: Sample plan running above the prompt, with sample routing until real ones arrive.
[-]
0: deck ▾ · 5 rows 22:11:41
⇄ Model route opus = opus jev: haiku · not applied effort ▁▃·· medi = kept ✕
✓ Orders module Done · 12/12 · 2/2 agents 100% ✕
● Context 44k / 200k 22% ✕
◔ Session · 5h 5h · 26% used ↻ 2:04:24 ✕
◔ Weekly · 7d 7d · 7% used ↻ 2d 0h 57m ✕
❯
⏵⏵ auto mode on (shift+tab to cycle) · ← for agents [ Deck 1 ]Claude Desktop

A cockpit for Claude Code: plan bars and subagent strips, context, usage limits with reset countdowns and burn rates, spend, the model route and a pet. Six bar styles, three collapsed looks. CLI and Desktop.
Terminal
❯ /flightdeck open
⎿ flightdeck: Flightdeck opened. Focus it with ctrl+x tab; 1-6 expand cards, f/s/o open the gate
rows.
╭────────────────────────────────────────────────────────────────────────────────────────────────✕─╮
│ Opus 4.8 ○ idle · ctx ▰▱▱▱▱▱ 22% · $0.25 │
│ last turn 0s · 0 agents · 0 edits · 0 errors │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
❯
⚠ flightdeck: ctx 22%Claude Desktop

Flightdeck: a live agent dashboard for Claude Code. Main model vitals, an on-call architect, every permission check, subagent cards and swimlanes, a turn receipt and a session log, all from real session events
Terminal
[-]
zZ
▀▄ ▄▀
▄▄▀▀▀▀▀▀▀▀▀▀ ▀▀▀▄▄▄
▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀
ctx 22% [ Pet ♥ ] [ ⚙ ] [ ↻ Adventurer ] [ Hide ]
❯ Claude Desktop

A little pixel cat that wanders above the Claude Code prompt, watches your usage limits and announces when work finishes; or switch packs for an adventurer who mines, chops trees and fights zombies