The vital signs of your Claude Code session — usage quota, context window, cost, git status and more, right in your terminal. Pure bash, zero Node, never blocks your prompt.
| ccvitals | Node-based statuslines | |
|---|---|---|
| Runtime | pure bash + jq | Node.js ≥ 14–18 |
| Render blocking | never — stale-while-revalidate cache, background refresh | varies |
| Rate-limit data | stdin first (zero-latency), OAuth API fallback | usually API calls |
| 1M context tier | detected — context % stays accurate past 200k | mostly assumes 200k |
| Two-line layout | yes | rare |
| Install | plugin marketplace or git clone + symlink (git pull = update) |
npx / npm |
Install ccvitals as a Claude Code plugin — no cloning or manual config required:
/plugin marketplace add educlopez/ccvitals
/plugin install ccvitals@ccvitals
/ccvitals:setup
/ccvitals:setup asks which modules you want, writes the config, and wires up settings.json automatically. Then restart Claude Code.
To reconfigure modules or switch to a two-line layout later:
/ccvitals:configure
brew install educlopez/tap/ccvitals
ccvitals # interactive installer (or: ccvitals --all)After brew upgrade ccvitals, run ccvitals --force once to relink. Remove with ccvitals uninstall.
If you prefer a git-clone workflow (symlinked install, instant git pull updates):
git clone https://github.com/educlopez/ccvitals.git
cd ccvitals
./install.shThe installer shows an interactive menu where you pick which modules to enable:
ccvitals — Choose your modules:
[x] 1) Directory my-project
[x] 2) Model Opus 4.6
[x] 3) Context ░░░░░░░░░░░░░░░ 12%
[x] 4) Usage quota Max ██████░░░░ 58% 3h42m
[x] 5) Git status (main | 3 files +42 -8)
Toggle: enter number (e.g. 4). Accept: Enter. All: a
Then restart Claude Code.
# Force reinstall (relink script + overwrite settings.json statusLine key)
./install.sh --force
# Skip menu — install all modules
./install.sh --all
# Skip menu — pick specific modules
./install.sh --modules=model,context,usage
# Two-line layout (these modules drop to row 2)
./install.sh --all --line2=context,usage,rtk,mode,lines
# Combine flags
./install.sh --force --modules=context,usage,gitThe interactive installer also asks, after you pick your modules, which of them should drop to a second line (enter their numbers, or press Enter for a single line).
cd ccvitals && git pullBecause the script is symlinked, git pull updates the statusline instantly —
no reinstall needed. Restart Claude Code to see the new version.
Run /ccvitals:configure (plugin install) or re-run the installer with --force. You can also edit ~/.claude/.statusline-config.json directly:
{
"modules": ["directory", "model", "context", "usage", "git", "rtk", "codegraph", "lines", "mode", "cost", "duration", "speed", "vim", "agent", "pr", "weekly"]
}Remove any module from the array to hide it.
Add an optional modules_line2 array to render those modules on a second row. Modules stay in modules for line 1; anything in modules_line2 drops to line 2. Omit modules_line2 entirely for a single line.
{
"modules": ["directory", "model", "git", "codegraph"],
"modules_line2": ["context", "usage", "rtk", "mode", "lines"]
}Renders as:
my-project | Opus 4.6 | (main | 3 files +42 -8) | ⬡ 11.7k
███░░ 21% ⚠ | Max 58% 3h42m | rtk 86.8%↓ | ⚡ xhigh | +264 -195
Add an optional module_order array to control the left-to-right display order of modules. Any enabled module not listed is appended after the listed ones in the default order — so you can pin just the modules you care about without listing everything.
{
"modules": ["directory", "model", "context", "git", "cost"],
"module_order": ["cost", "git", "context", "model", "directory"]
}Rules:
- Unknown names in
module_orderare silently ignored (forward-compatible with future modules). modules_line2assignment is independent —module_ordercontrols sequence, not which line a module lands on.- Works with powerline mode.
- When
module_orderis absent the default order is preserved byte-for-byte.
| Module | What it shows |
|---|---|
directory |
Current project folder name |
model |
Active model (Opus 4.6, Sonnet 4.6, etc.) |
context |
Context window progress bar + percentage (default); set "context_display": "tokens" for 26.0k/200k format, or "both" for 26.0k/200k 13%; turns red with a ⚠ when the context is large (≥90%) |
usage |
5h quota bar, reset timer, plan badge (Pro/Max/Team), 7d warning |
git |
Branch name, changed files count, lines added/removed; when an upstream exists, shows ↑N ↓M ahead/behind counts (GREEN/YELLOW); branch name is a clickable OSC 8 link on GitHub/GitLab remotes |
rtk |
RTK token-savings % — e.g. rtk 86.8%↓ (needs the rtk CLI) |
codegraph |
CodeGraph index size + stale marker — e.g. ⬡ 11.7k ⚠3 (needs the codegraph CLI; only shows in indexed projects) |
lines |
Lines added/removed this session — e.g. +264 -195 (cumulative agent edits, distinct from the git working-tree diff) |
mode |
Reasoning effort level + fast-mode flag — e.g. ⚡ xhigh |
cost |
Session cost in USD — e.g. $0.42 (from stdin, zero-latency) |
duration |
Session wall-clock time — e.g. 1h23m (from stdin, zero-latency) |
speed |
Token throughput — e.g. 42 tok/s (delta between renders, cached per session) |
vim |
Vim mode indicator — N / I / V / VL with distinct colors |
agent |
Active agent name — e.g. @ my-agent (hidden when no agent active) |
pr |
Linked PR number and review state — e.g. PR #123 approved (hidden when absent); PR #N is a clickable OSC 8 hyperlink when pr.url is present |
weekly |
7-day quota bar with reset countdown — e.g. 7d: ████░░░░░░ 38% 4d2h |
pace |
Burn-rate vs 5h quota window — e.g. pace +12% (GREEN = under budget, YELLOW = slightly over, RED = burning fast); hidden when rate_limits absent |
cache |
Prompt-cache freshness countdown — e.g. cache 4m12s or cache cold (reads transcript_path from stdin; hidden when absent) |
tools |
Tools currently in flight — e.g. ⚒ Bash (one pending) or ⚒ Bash +2 (first + overflow count); Skill invocations show the skill name in YELLOW (e.g. ⚒ deploy-to-vercel); MCP tool names are compacted from mcp__server__tool to server:tool; hidden when none pending; reads the last 300 lines of the transcript (never full file) |
agents |
Active sub-agents — e.g. ◉ code-reviewer (one) or ◉ 3 agents (several); hidden when none; reads transcript (tail-bounded) |
todos |
Latest TodoWrite progress — e.g. ☑ 3/7; GREEN when all done, CYAN otherwise; hidden when no TodoWrite found; reads transcript (tail-bounded) |
workflows |
Running Workflow orchestrations — e.g. ⟳ 1 wf (one running) or ⟳ 3 wf (several); hidden when none pending; reads transcript (tail-bounded, same single jq pass as tools/agents/todos) |
daily |
Cross-session daily spend — e.g. Σ $4.20; with optional daily_budget config: Σ $4.20/$10 colored GREEN/YELLOW/MAGENTA/RED by budget %age; prunes day-files older than 7 days |
compactions |
Count of /compact events in the transcript — e.g. ↯ 2; hidden when 0; uses grep -c on the full file (fast, no jq) |
tokens |
Cumulative session input/output tokens — e.g. ⇅ 1.2M/45k; incremental cache keyed by session; resets on compact; hidden when transcript absent |
thinking |
Reasoning effort level with an icon — e.g. ✦ xhigh; hidden when absent; color: CYAN for xhigh, MAGENTA for high, GRAY otherwise; reads .effort.level (or .thinking_effort as fallback) |
mcp |
Configured MCP server count — e.g. ⬡ 4; counts servers from .mcp.json in the project root, ~/.claude.json, and ~/.claude/settings.json; hidden when count is zero; result is mtime-cached for zero-cost renders (count-only — health checking via claude mcp list is too slow for the render path) |
spend |
7-day and 30-day historical spend — e.g. 7d $12.40 · 30d $48; reads per-day ledger files written by the daily module; accumulation starts from when daily was first enabled; configurable windows via spend_windows; hidden when ledger dir absent |
session |
Session title written by ccvitals-hook.sh — e.g. § my-refactor; hidden when hooks not installed or no title set; add "session_turns": true to also show turn counter (§ my-refactor ·12); requires --hooks |
rtk,codegraph,lines,mode,cost,duration,speed,vim,agent,pr,weekly,pace,cache,tools,agents,todos,workflows,daily,compactions,tokens,thinking,mcp,spend, andsessionare opt-in (off by default).rtkandcodegraphcache their output (rtk 60s globally, codegraph 15s per project) and refresh in the background, so they don't slow down rendering; each silently hides itself when its CLI isn't installed.tools,agents,todos, andworkflowsshare onetail -n 300+ onejqinvocation of the transcript per render, keeping the cost bounded regardless of transcript size.compactionsusesgrep -con the full transcript (fast, O(n) line scan).tokensprocesses only new lines since the last render (incremental cache, negligible per-render cost).mcpuses mtime-based file cache so parsing only happens when config files change.
- Modular — pick only the sections you want
- Context window — progress bar + percentage of context used
- Usage quota — 5-hour utilization with color-coded bar (Pro/Max/Team)
- Reset timer — countdown to when your 5h quota resets
- 7-day warning — shows weekly utilization when above 70%
- Git status — branch name, changed files count, lines added/removed
- Plan badge — shows your subscription tier (Pro, Max, Team)
- Smart caching — usage data cached for 60s, refreshed in background
- Cross-platform — works on macOS, Linux, and WSL
| Usage level | Color |
|---|---|
| 0-49% | Cyan |
| 50-74% | Yellow |
| 75-89% | Magenta |
| 90%+ | Red |
ccvitals ships with six built-in color presets plus a custom mode. Set the "theme" key in ~/.claude/.statusline-config.json:
Why does
defaultlook different on my machine? Thedefaulttheme emits classic 16-color ANSI codes, so your terminal's palette decides the final colors — it blends in with whatever theme your terminal uses. The named presets use fixed truecolor values and look identical in every terminal.
Switch theme by running /ccvitals:configure (plugin install) or editing the config directly:
{
"modules": ["directory", "model", "context", "usage", "git"],
"theme": "tokyo-night"
}Create a .ccvitals.json file at your project's workspace root to override any global config keys for that project. Any key present in the project file wins; absent keys keep their global values.
{ "theme": "dracula", "smart": true, "modules": ["directory", "model", "context", "git"] }Supported keys: modules, modules_line2, module_order, theme, colors, powerline, powerline_separator, context_display, pace_display, daily_budget, session_budget, spend_windows, weekly_split, smart, icons, responsive, git_operation, git_status_split, git_sha, git_stash, git_age.
The merge uses jq -s '.[0] * .[1]' (global * project). Values are only consumed as JSON data — never executed.
Set "powerline": true in ~/.claude/.statusline-config.json to render each module as a shaded segment separated by the Nerd Font arrow glyph (U+E0B0, ``) instead of |:
{
"modules": ["directory", "model", "context", "usage", "git"],
"theme": "tokyo-night",
"powerline": true
}Segments alternate between two background shades drawn from the active theme. Each inter-segment boundary gets a glyph whose foreground color matches the previous segment's background, creating a seamless chevron effect. A final trailing arrow resets to the terminal default background.
Nerd Font required — the `` glyph renders correctly only when your terminal uses a Nerd Font (e.g. JetBrainsMono Nerd Font, FiraCode Nerd Font, MesloLGS NF). Without one the separator appears as a box or question mark.
When Claude Code spawns sub-agents (e.g. during /sdd-apply, multi-agent workflows, or background tasks), it shows an agent panel below the prompt. ccvitals replaces the default name · description · tokens row for each sub-agent with a richer, theme-aware row:
◐ code-reviewer Reviewing the auth module for security issues 1.2k myproject
✓ formatter Formatting complete 5.2M other
Each row shows:
- Status icon —
◐CYAN (running),✓GREEN (completed),✗RED (stopped/failed),·GRAY (unknown) - Label or name of the sub-agent
- Description — truncated so the whole row fits within the available terminal width
- Token count —
1.2k/5.2Mformat; hidden when zero - Project folder — basename of the sub-agent's working directory
This is enabled automatically when you install ccvitals via ./install.sh or /ccvitals:setup. The rows respect your active theme.
To keep Claude Code's default sub-agent panel, remove the subagentStatusLine key from ~/.claude/settings.json:
jq 'del(.subagentStatusLine)' ~/.claude/settings.json > ~/.claude/settings.json.tmp \
&& mv ~/.claude/settings.json.tmp ~/.claude/settings.jsonOverride the separator glyph with any string via "powerline_separator":
{
"modules": ["directory", "model", "context"],
"powerline": true,
"powerline_separator": "▶"
}Use a plain ASCII fallback (e.g. "|" or ">") if you don't have a Nerd Font installed.
Set "theme": "custom" and supply a "colors" object with any of the seven color keys (red, green, blue, yellow, cyan, gray, magenta). Missing keys fall back to the default palette. Values must be #RRGGBB hex strings:
{
"modules": ["directory", "model", "context", "usage", "git"],
"theme": "custom",
"colors": {
"blue": "#7aa2f7",
"green": "#9ece6a",
"magenta": "#bb9af7",
"cyan": "#7dcfff",
"yellow": "#e0af68",
"red": "#f7768e",
"gray": "#565f89"
}
}Truecolor terminals (iTerm2, Kitty, WezTerm, most modern Linux terminals) display the full RGB palette. The default and mono presets use the classic 16-color ANSI codes and work on every terminal.
Some modules accept additional config keys in .statusline-config.json:
{ "pace_display": "eta" }| Value | Display | Description |
|---|---|---|
"delta" (default) |
pace +12% |
How far ahead/behind the expected burn rate |
"eta" |
⌛ ~17:40 / ⌛ ok |
Estimated exhaustion time — RED if within 1h, YELLOW otherwise, GREEN if quota outlasts the reset |
{ "daily_budget": 10 }Optional USD budget for the daily module. When set, displays Σ $4.20/$10 with color:
GREEN <50%, YELLOW <80%, MAGENTA <100%, RED ≥100%.
{ "session_budget": 5 }Optional USD budget for the cost module. When set, the cost segment shows $1.50/$5.00 (current / cap) with color:
GRAY <50%, YELLOW 50–79%, RED ≥80%.
When unset, cost renders exactly as before ($0.42 in GRAY).
{ "spend_windows": ["7d", "30d"] }Controls which time windows the spend module displays. Supported values: "7d", "30d". Default: both.
{ "spend_windows": ["7d"] }The
spendmodule reads the per-day ledger thatdailywrites to~/.claude/.ccvitals-daily/. Historical data only accumulates from whendailywas first enabled — there is no automatic backfill of earlier transcripts.
{ "weekly_split": true }When true and the OAuth cache contains seven_day_opus/seven_day_sonnet utilization, displays 7d O:42% S:18% instead of the single progress bar. Falls back to the bar when per-model data is unavailable (note: requires the OAuth fetch path to have run at least once).
{ "tools_skill_names": false }When true (default), a pending Skill tool invocation renders its .input.skill argument (e.g. ⚒ deploy-to-vercel) in YELLOW instead of the generic label. Set to false to always show Skill in CYAN, like any other tool.
MCP tool names (mcp__server__tool) are always compacted to server:tool regardless of this setting.
{ "smart": true }When true, modules only appear when their value is notable. Default: false (behavior identical to before).
| Module | Visible when |
|---|---|
cost |
≥ $1.00 |
cache |
remaining < 60s, or cold |
pace (delta mode) |
delta < 0 (burning fast) |
context |
≥ 50% |
duration |
≥ 1 hour |
thinking |
effort is high or xhigh (low/medium hidden) |
All other modules are unaffected. ETA mode (pace_display: "eta") always shows when enabled.
{ "icons": "ascii" }| Value | Description |
|---|---|
"unicode" (default) |
Current glyphs: ⚒ ◉ ☑ ⌛ ⇅ ↯ ⚡ ⚠ █░ ↑↓ — byte-identical to no-config |
"ascii" |
Plain ASCII: T: A: [x] eta io cmp ! (!) #- +/- |
"nerd" |
Nerd Font icons (requires a Nerd Font in your terminal) |
{ "responsive": true }When true and COLUMNS is set, ccvitals drops the lowest-priority modules from line 1 until the visible output fits within the terminal width. Priority order (dropped first → last):
thinking → mcp → codegraph → rtk → lines → duration → cost → speed → vim → weekly → daily → spend → tokens → compactions → pr → agent → mode → cache → pace → tools → agents → todos → workflows → git → usage → context → model → directory
Note: Powerline mode + responsive is not yet supported — responsive is silently skipped when
powerline: true.
Each option is a boolean key in .statusline-config.json (or .ccvitals.json):
| Key | What it adds |
|---|---|
git_operation |
Banner before the git segment when a merge/rebase/cherry-pick/bisect is in progress — e.g. MERGE (main …) in RED |
git_status_split |
Replaces the N files aggregate with staged/unstaged/untracked counts — e.g. +2 ~3 ?1 (GREEN/YELLOW/GRAY); uses the existing git status --porcelain pass, no extra subprocess |
git_sha |
Appends the short commit SHA — e.g. abc1234 in GRAY |
git_stash |
Appends stash count when > 0 — e.g. ≡2 in GRAY; hidden when stash is empty |
git_age |
Appends time since last commit, compact format — e.g. 5m / 2h / 3d / 4w in GRAY |
Example — enable multiple extras at once:
{
"modules": ["git"],
"git_operation": true,
"git_status_split": true,
"git_sha": true,
"git_stash": true,
"git_age": true
}All five extras use a single git status --porcelain pass (already needed for the base module). Only git_sha, git_stash, and git_age add one lightweight subprocess each.
{ "session_turns": true }When true, the session module appends a turn counter derived from message_count in the hook state file (e.g. § my-refactor ·12). Default: false. Requires hooks to be installed.
ccvitals ships an optional hook script (ccvitals-hook.sh) that Claude Code calls on every event. This is pure opt-in infrastructure: nothing is wired unless you ask.
Claude Code hooks (v2.1.84+ for TaskCreated, v2.1.152+ for MessageDisplay) fire a script on session and message events. ccvitals-hook.sh listens and writes per-session state to ~/.claude/.ccvitals-state/<session_id>.json. Statusline modules read that file at zero parse cost — no extra process needed.
Currently powered by hooks:
| Module | What it shows | Requires hooks |
|---|---|---|
session |
Session title from /rename or SessionStart payload (e.g. § my-refactor) |
yes |
session + session_turns: true |
Session title + turn counter (e.g. § my-refactor ·12) |
yes |
./install.sh --hooks # wire hooks only (add to an existing install)
./install.sh --all --hooks # all modules + hooks in one passOr use the interactive installer — it asks whether to wire hooks after the module menu.
The hook script is registered in ~/.claude/settings.json under the hooks key for these events: SessionStart, MessageDisplay, TaskCreated, PostCompact, Stop. Any existing hooks you have for those events are preserved — ccvitals only appends its entry if not already present.
{ "modules": ["session", "model", "context", "git"] }With turn counter:
{ "modules": ["session", "model", "context"], "session_turns": true }The module is silently hidden when hooks are not installed or the state file is absent — no errors.
./uninstall.sh removes only the ccvitals hook entries from settings.json (matching by script path) and deletes ~/.claude/.ccvitals-state/. Your other hooks are untouched.
All data stays local. The hook script reads event JSON from stdin and writes only to ~/.claude/.ccvitals-state/ — no network calls, no external services. State files are cleaned up automatically after 48 hours.
- Claude Code CLI
jq— JSON processor (install)git— to clone and update the repobash3.2+ (pre-installed on most systems)
The statusline itself uses
curlat runtime to fetch your usage quota, but the installer no longer downloads anything — it links the clonedstatusline.sh.
- Claude Code pipes JSON context (model, workspace, context window) to the script via stdin
- The script reads
~/.claude/.statusline-config.jsonto know which modules are enabled - For the usage/weekly modules: prefers
rate_limitsdata straight from Claude Code's stdin JSON (zero-latency, no network). When absent, falls back to fetching quota from the Anthropic API with OAuth credentials:- macOS (Claude Code 2.x+): reads from the macOS Keychain using profile-specific service names
- Fallback: reads from
~/.claude/.credentials.json(older Claude Code versions or non-macOS)
- Usage data is cached locally (
~/.claude/.usage-cache/usage.json) for 60 seconds to avoid blocking the statusline - Git info is gathered from the current workspace directory
- Only enabled modules are rendered into the final colorized line
If you use CLAUDE_CONFIG_DIR to manage multiple accounts, the statusline respects it:
CLAUDE_CONFIG_DIR=~/.claude-work claudeThe installer also respects CLAUDE_CONFIG_DIR — run it with the variable set to install for a specific account. Each account gets its own module config.
| Platform | Status |
|---|---|
| macOS | Supported |
| Linux | Supported |
| WSL | Supported |
| Windows (via Git Bash) | Supported |
From the cloned repo:
./uninstall.shThis removes the statusline symlink, module config, the statusLine key from your settings, and the usage cache directory. (The cloned repo is left untouched — delete it manually if you no longer want it.)
MIT








