https://github.com/jimmyolo/cc-statusline
Multi-line ANSI statusline renderer for Claude Code — model, cost, context, rate limits, tokens, agents/tools/todos in 3-4 lines
https://github.com/jimmyolo/cc-statusline
bash claude-code jq statusline
Last synced: 22 days ago
JSON representation
Multi-line ANSI statusline renderer for Claude Code — model, cost, context, rate limits, tokens, agents/tools/todos in 3-4 lines
- Host: GitHub
- URL: https://github.com/jimmyolo/cc-statusline
- Owner: jimmyolo
- License: unlicense
- Created: 2026-05-11T06:04:24.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-19T12:16:12.000Z (about 1 month ago)
- Last Synced: 2026-05-19T15:11:13.461Z (about 1 month ago)
- Topics: bash, claude-code, jq, statusline
- Language: Shell
- Size: 34.2 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# cc-statusline
A multi-line, ANSI-colored statusline renderer for [Claude Code](https://claude.com/claude-code), written in pure `bash` + `jq`. Surfaces model, cost, context, rate limits, token usage, cache hit rate, live agent/tool/todo activity, and the last prompt — all in 3–4 lines.
## Sample output
```
Opus 4.7 (1M context) (H) 1M v1.2.3 | repo (main) | +42 -7 lines | 3A | NOR
●●●◐●●●●●● 35% | $1.23 (today $5.67) | 5h 23% (2h 14m) | 7d 57% (5d 8h)
cache 97% | in: 123.4K out: 7.8K | api wait 30m 00s (50%) | agents 2 reviewer-opus-high,coder-sonnet-max
tools Read,Bash | todos 3/7 fix smoke test | 14:23 ❯ update README sample output
```
L3 groups "session-wide consumption" (cache, tokens, api wait) plus the active subagent indicator. L4 groups "live activity & user intent" (currently running tools, todo progress, last prompt). Both lines render conditionally — empty fields drop out.
The `agents …` indicator on L3 is dual-mode: **magenta** while subagent(s) are running (`agents N name1,name2`), **dim** as a fallback showing the most recent subagent_type once they finish — so the field doesn't vanish the moment a subagent completes.
## Requirements
- `bash` 4+
- `jq`
- `bc` (for token K/M formatting)
- `git` (optional — enables branch / repo-link / diff stats)
- A terminal that renders ANSI color + OSC 8 hyperlinks (most modern terminals do)
## Install
```bash
# 1. Clone anywhere
git clone https://github.com/jimmyolo/cc-statusline.git ~/projects/cc-statusline
# 2. Symlink into ~/.claude/ (or copy — symlink lets `git pull` pick up updates)
ln -s ~/projects/cc-statusline/cc-statusline.sh ~/.claude/cc-statusline.sh
# 3. Wire up in ~/.claude/settings.json
# Add (or merge into existing settings):
# {
# "statusLine": {
# "type": "command",
# "command": "bash ~/.claude/cc-statusline.sh"
# }
# }
```
Statusline is hot-reloaded — next refresh picks up the new script. No session restart needed.
## Field reference
The script reads 22 fields from the JSON Claude Code pipes to its `statusLine.command` on stdin. Each field maps to a specific display block:
| Field | JSON path | Displayed in |
|---|---|---|
| `MODEL` | `.model.display_name` | L1 model badge |
| `DIR` | `.workspace.current_dir` | Repo-link basename fallback |
| `COST` | `.cost.total_cost_usd` | L2 cost + today tracker |
| `PCT` | `.context_window.used_percentage` | L2 context bar |
| `CTX_SIZE` | `.context_window.context_window_size` | L1 `1M`/`200K` label |
| `DURATION_MS` | `.cost.total_duration_ms` | L3 api-wait %, plus disabled blocks |
| `LINES_ADD` / `LINES_DEL` | `.cost.total_lines_{added,removed}` | L1 `+N -N lines` |
| `VIM_MODE` | `.vim.mode` | L1 NOR / INS |
| `VERSION` | `.version` | L1 `vX.Y.Z` |
| `RATE_5H` / `RATE_7D` | `.rate_limits.{five_hour,seven_day}.used_percentage` | L2 rate-limit % |
| `RESET_5H` / `RESET_7D` | `.rate_limits.{five_hour,seven_day}.resets_at` | L2 countdown |
| `TOTAL_IN_TOKENS` / `TOTAL_OUT_TOKENS` | `.context_window.total_{input,output}_tokens` | L3 `in:` / `out:` |
| `API_DURATION_MS` | `.cost.total_api_duration_ms` | L3 api wait |
| `CACHE_READ` / `CACHE_CREATE` / `CUR_INPUT` | `.context_window.current_usage.*` | L3 cache hit (cur detail disabled by default) |
| `SESSION_ID` | `.session_id` | Today-cost tracker + last-prompt lookup |
| `TRANSCRIPT_PATH` | `.transcript_path` | L3 agents · L4 tools · todos |
The full mapping (with paired-disable annotations) lives at the top of [`cc-statusline.sh`](cc-statusline.sh).
## Layout
| Line | Contents |
|---|---|
| L1 | model · ctx-size · version · repo-link · branch · lines · git-stats · vim |
| L2 | context-bar · cost (session + today) · 5h limit · 7d limit |
| L3 | cache-hit · tokens in/out · api wait · agents (magenta=running, dim=last seen) |
| L4 | running tools · todos (with current task) · last prompt (with `❯` marker) — entire line conditionally rendered |
Disabled by default (one-line uncomment to re-enable — see [Customization](#customization)): per-message duration (`DUR`), tokens-per-minute burn rate, and current-usage detail (`cur N in / N read / N write`).
## Customization
The script is annotated for surgical edits:
- **Field map at the top** — see which `F[N]` feeds which line.
- **Inline `# → L` comments** on every variable assignment.
- **`# INPUTS:` banner** above each `L1`/`L2`/`L3`/`L4` block lists every variable that line consumes.
- **`Paired-disable note`** above each disabled block (Duration, Burn rate, cur-detail) tells you whether the underlying `F[N]` extraction can be commented out too.
To disable a display block:
1. Comment out the relevant `L1=`/`L2=`/`L3=`/`L4=` concat line(s).
2. Check the field map — if any `F[N]` is consumed *only* by what you disabled, comment its extraction too.
3. Re-run the smoke test (`bash test/smoke.sh`) to confirm no regression.
To re-enable the bundled disabled blocks (Duration, Burn rate, cur-detail):
1. Uncomment the block body.
2. For `DUR` / `BURN_PART`: inject the produced variable into the desired `L1`–`L4` line. For `cur-detail`: the block already self-appends to `L3` — just uncomment the four lines in place.
## Testing
```bash
bash test/smoke.sh
```
Runs the script against `test/sample.json` and asserts:
- Output contains at least 3 non-empty lines.
- Output contains expected markers (model name, version, context size, cost).
- Script does not crash.
The smoke test is robust to volatile fields (today-cost tracker, countdown timers) by checking for structural markers rather than exact byte equality.
## License
[The Unlicense](LICENSE) — public domain, do whatever.
## Acknowledgements
Inspired by `claude-dashboard`'s per-session cost aggregation logic. Layout & feature set hand-tuned for personal workflow.