cc-context-stats 1.10.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.backup.md +324 -0
- package/README.md +332 -101
- package/package.json +1 -1
- package/scripts/context-stats.sh +6 -1
- package/scripts/statusline.js +157 -42
package/README.backup.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="assets/logo/logo-full.svg" alt="cc-context-stats" width="320"/>
|
|
3
|
+
|
|
4
|
+
<h1>Stop Shipping from a Half-Blind Model</h1>
|
|
5
|
+
|
|
6
|
+
<p><strong>Real-time model intelligence monitoring for Claude Code.</strong><br/>Know exactly when your model is at peak quality — and when it's time for a fresh session.</p>
|
|
7
|
+
|
|
8
|
+
[](https://pypi.org/project/cc-context-stats/)
|
|
9
|
+
[](https://www.npmjs.com/package/cc-context-stats)
|
|
10
|
+
[](https://pypi.org/project/cc-context-stats/)
|
|
11
|
+
[](https://www.npmjs.com/package/cc-context-stats)
|
|
12
|
+
[](https://github.com/luongnv89/cc-context-stats)
|
|
13
|
+
[](https://opensource.org/licenses/MIT)
|
|
14
|
+
|
|
15
|
+
[**Get Started in 60 Seconds →**](#installation)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
## The Problem
|
|
24
|
+
|
|
25
|
+
You're deep into a Claude Code session — refactoring, debugging, shipping. Everything feels fine. But behind the scenes:
|
|
26
|
+
|
|
27
|
+
- **Your model is getting dumber and you can't see it.** Research shows LLM retrieval accuracy drops as the context window fills. Claude starts missing details, hallucinating references, and losing track of your codebase — silently.
|
|
28
|
+
- **You don't know when to start fresh.** Is 50% context usage safe? 70%? It depends on the model. Opus holds quality longer than Sonnet, which degrades faster than Haiku. Without data, you're guessing.
|
|
29
|
+
- **Wasted sessions cost real money.** Pushing through a degraded context means more back-and-forth, more corrections, more tokens burned on worse output. You pay more for less.
|
|
30
|
+
|
|
31
|
+
You can't fix what you can't measure.
|
|
32
|
+
|
|
33
|
+
## How cc-context-stats Fixes This
|
|
34
|
+
|
|
35
|
+
cc-context-stats gives you a **Model Intelligence (MI) score** — a single number from 1.000 to 0.000 that tells you how sharp your model is right now, calibrated from Anthropic's [MRCR v2 8-needle](https://docs.anthropic.com/) retrieval benchmark.
|
|
36
|
+
|
|
37
|
+
- **One glance, full picture** — MI score lives in your Claude Code status bar. Green means sharp. Yellow means degrading. Red means stop and start fresh.
|
|
38
|
+
- **Per-model awareness** — Opus (beta=1.8) retains quality longest. Sonnet (beta=1.5) is moderate. Haiku (beta=1.2) degrades earliest. MI reflects your actual model automatically.
|
|
39
|
+
- **Live dashboard** — ASCII graphs track context growth, MI degradation, and token I/O over time. Watch quality erode in real-time so you can make informed decisions.
|
|
40
|
+
- **Zero config, zero dependencies** — Install in one command. Works with pip, npm, or a shell script. No API keys, no network calls. All data stays local.
|
|
41
|
+
- **Context zones** — Five-state indicators tell you where you stand:
|
|
42
|
+
|
|
43
|
+
| Zone | Indicator | Color | What It Means |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| **Planning** | Plan | Green | Safe to plan and code |
|
|
46
|
+
| **Code-only** | Code | Yellow | Avoid starting new plans |
|
|
47
|
+
| **Dump zone** | Dump | Orange | Quality declining — finish up |
|
|
48
|
+
| **Hard limit** | ExDump | Dark red | Start a new session now |
|
|
49
|
+
| **Dead zone** | Dead | Gray | Nothing productive here |
|
|
50
|
+
|
|
51
|
+
[**Install and See Your MI Score →**](#installation)
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
1. **Install** — One command: `pip install cc-context-stats` or `npm install -g cc-context-stats`
|
|
56
|
+
2. **Configure** — Add the statusline command to `~/.claude/settings.json` (two lines of JSON)
|
|
57
|
+
3. **Restart Claude Code** — MI score and context stats appear in your status bar immediately
|
|
58
|
+
4. **Monitor** — Run `context-stats <session_id>` for a live dashboard with graphs, zone status, and session summary
|
|
59
|
+
|
|
60
|
+
| Status Bar (green — model is sharp) | Status Bar (yellow — quality degrading) |
|
|
61
|
+
|:---:|:---:|
|
|
62
|
+
|  |  |
|
|
63
|
+
|
|
64
|
+
| Delta Graph | Cumulative Graph |
|
|
65
|
+
|:---:|:---:|
|
|
66
|
+
|  |  |
|
|
67
|
+
|
|
68
|
+
[**See Full CLI Options →**](#context-stats-cli)
|
|
69
|
+
|
|
70
|
+
## Model Intelligence — The Science
|
|
71
|
+
|
|
72
|
+
MI isn't a guess. It's derived from `MI(u) = max(0, 1 - u^beta)` where `u` is context utilization and `beta` is a model-specific degradation rate calibrated against Anthropic's MRCR v2 8-needle long-context retrieval benchmark.
|
|
73
|
+
|
|
74
|
+
| Model | Beta | MI at 50% Context | MI at 75% Context | When to Worry |
|
|
75
|
+
|-------|------|-----------|-----------|---------------|
|
|
76
|
+
| Opus | 1.8 | 0.713 | 0.404 | ~60% used |
|
|
77
|
+
| Sonnet| 1.5 | 0.646 | 0.350 | ~50% used |
|
|
78
|
+
| Haiku | 1.2 | 0.565 | 0.292 | ~45% used |
|
|
79
|
+
|
|
80
|
+
The model is auto-detected from your session. See [Model Intelligence docs](docs/MODEL_INTELLIGENCE.md) for the full formula and benchmark data.
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
### Shell Script (quickest)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
curl -fsSL https://raw.githubusercontent.com/luongnv89/cc-context-stats/main/install.sh | bash
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### npm
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install -g cc-context-stats
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Python
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install cc-context-stats
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Or with uv:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv pip install cc-context-stats
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Verify Installation
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
curl -fsSL https://raw.githubusercontent.com/luongnv89/cc-context-stats/main/scripts/check-install.sh | bash
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Quick Start
|
|
115
|
+
|
|
116
|
+
Add to `~/.claude/settings.json`:
|
|
117
|
+
|
|
118
|
+
**pip or npm install:**
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"statusLine": {
|
|
122
|
+
"type": "command",
|
|
123
|
+
"command": "claude-statusline"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Shell script install (`install.sh`):**
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"statusLine": {
|
|
132
|
+
"type": "command",
|
|
133
|
+
"command": "~/.claude/statusline.sh"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Restart Claude Code. MI score and context stats appear in your status bar immediately.
|
|
139
|
+
|
|
140
|
+
### Real-Time Dashboard
|
|
141
|
+
|
|
142
|
+
Get your session ID from the status line (the last part after the pipe `|`), then:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
context-stats <session_id>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Context Stats (my-project • abc123def)
|
|
150
|
+
|
|
151
|
+
Context Growth Per Interaction
|
|
152
|
+
Max: 4,787 Min: 0 Points: 254
|
|
153
|
+
...graph...
|
|
154
|
+
|
|
155
|
+
Session Summary
|
|
156
|
+
----------------------------------------------------------------------------
|
|
157
|
+
Context Remaining: 43,038/200,000 (21%)
|
|
158
|
+
>>> DUMB ZONE <<< (You are in the dumb zone - Dex Horthy says so)
|
|
159
|
+
Model Intelligence: 0.646 (Context pressure building, consider wrapping up)
|
|
160
|
+
Context: 79% used
|
|
161
|
+
|
|
162
|
+
Last Growth: +2,500
|
|
163
|
+
Input Tokens: 1,234
|
|
164
|
+
Output Tokens: 567
|
|
165
|
+
Lines Changed: +45 / -12
|
|
166
|
+
Total Cost: $0.1234
|
|
167
|
+
Model: claude-sonnet-4-6
|
|
168
|
+
Session Duration: 2h 29m
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
[**See All Graph Types and Options →**](#context-stats-cli)
|
|
172
|
+
|
|
173
|
+
## Context Stats CLI
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
context-stats # Live monitoring (default)
|
|
177
|
+
context-stats -w 5 # Custom refresh interval (5 seconds)
|
|
178
|
+
context-stats --no-watch # Show once and exit
|
|
179
|
+
context-stats --type cumulative # Show cumulative context usage
|
|
180
|
+
context-stats --type both # Show both graphs
|
|
181
|
+
context-stats --type mi # Model Intelligence over time
|
|
182
|
+
context-stats --type all # Show all graphs including I/O and MI
|
|
183
|
+
context-stats <session_id> # View specific session
|
|
184
|
+
context-stats explain # Diagnostic dump (pipe JSON to stdin)
|
|
185
|
+
context-stats --version # Show version
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## FAQ
|
|
189
|
+
|
|
190
|
+
**Is it free?**
|
|
191
|
+
Yes. MIT licensed, zero dependencies, free forever. [See the license](LICENSE).
|
|
192
|
+
|
|
193
|
+
**Does it send my data anywhere?**
|
|
194
|
+
No. All data stays local in `~/.claude/statusline/`. No network requests, no telemetry, no API keys required.
|
|
195
|
+
|
|
196
|
+
**Is it actively maintained?**
|
|
197
|
+
Very. 11 releases since January 2025, with MI per-model profiles, configurable colors, state rotation, and cross-implementation parity tests all shipped in the last few months.
|
|
198
|
+
|
|
199
|
+
**How does it compare to just watching the context counter?**
|
|
200
|
+
The raw context counter tells you how full the window is. MI tells you how much quality you've lost — which depends on the model. 50% context on Opus (MI: 0.713) is fine. 50% on Haiku (MI: 0.565) means you should start wrapping up. cc-context-stats gives you the nuance.
|
|
201
|
+
|
|
202
|
+
**Can I use it with Opus, Sonnet, and Haiku?**
|
|
203
|
+
Yes. MI auto-detects your model and applies the correct degradation curve. Each model has a calibrated beta value from benchmark data.
|
|
204
|
+
|
|
205
|
+
**What runtimes does it support?**
|
|
206
|
+
Python (pip), Node.js (npm), or pure Bash. The statusline scripts are implemented in all three languages so you can use whichever runtime you have available.
|
|
207
|
+
|
|
208
|
+
**How do I customize colors?**
|
|
209
|
+
Create `~/.claude/statusline.conf` with named colors or hex codes. See [Configuration docs](docs/configuration.md) for all options.
|
|
210
|
+
|
|
211
|
+
## Start Shipping with Confidence
|
|
212
|
+
|
|
213
|
+
You wouldn't deploy without monitoring your servers. Don't code without monitoring your model.
|
|
214
|
+
|
|
215
|
+
cc-context-stats is MIT licensed, has zero dependencies, installs in one command, and works with any Claude Code setup. If you don't like it, `pip uninstall cc-context-stats` and it's gone.
|
|
216
|
+
|
|
217
|
+
[**Install cc-context-stats Now →**](#installation)
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary><strong>Status Line Components</strong></summary>
|
|
223
|
+
|
|
224
|
+
The status line shows at-a-glance metrics in your Claude Code interface:
|
|
225
|
+
|
|
226
|
+
| Component | Description |
|
|
227
|
+
| --------- | ----------------------------------------- |
|
|
228
|
+
| Model | Current Claude model |
|
|
229
|
+
| Context | Tokens used / remaining with color coding |
|
|
230
|
+
| Delta | Token change since last update |
|
|
231
|
+
| MI | Model Intelligence score (per-model) |
|
|
232
|
+
| Git | Branch name and uncommitted changes |
|
|
233
|
+
| Session | Session ID for correlation |
|
|
234
|
+
|
|
235
|
+
Colors change based on MI score and context utilization — green when the model is sharp, yellow as quality degrades.
|
|
236
|
+
|
|
237
|
+
</details>
|
|
238
|
+
|
|
239
|
+
<details>
|
|
240
|
+
<summary><strong>Configuration</strong></summary>
|
|
241
|
+
|
|
242
|
+
Create `~/.claude/statusline.conf`:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
token_detail=true # Show exact token counts (vs abbreviated like "12.5k")
|
|
246
|
+
show_delta=true # Show token delta in status line
|
|
247
|
+
show_session=true # Show session ID
|
|
248
|
+
autocompact=true # Show autocompact buffer indicator
|
|
249
|
+
reduced_motion=false # Disable animations for accessibility
|
|
250
|
+
show_mi=false # Show Model Intelligence score (disabled by default)
|
|
251
|
+
mi_curve_beta=0 # Use model-specific profile (0=auto, or set custom beta)
|
|
252
|
+
|
|
253
|
+
# Custom colors - named colors or hex (#rrggbb)
|
|
254
|
+
color_green=#7dcfff
|
|
255
|
+
color_red=#f7768e
|
|
256
|
+
color_yellow=bright_yellow
|
|
257
|
+
|
|
258
|
+
# Per-property colors (override individual elements)
|
|
259
|
+
color_context_length=bold_white # Context remaining
|
|
260
|
+
color_project_name=cyan # Project directory
|
|
261
|
+
color_branch_name=green # Git branch
|
|
262
|
+
color_mi_score=yellow # MI score
|
|
263
|
+
color_separator=dim # Model, delta, session
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
</details>
|
|
267
|
+
|
|
268
|
+
<details>
|
|
269
|
+
<summary><strong>Migration from cc-statusline</strong></summary>
|
|
270
|
+
|
|
271
|
+
If you were using the previous `cc-statusline` package:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
pip uninstall cc-statusline
|
|
275
|
+
pip install cc-context-stats
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The `claude-statusline` command still works. The main change is `token-graph` is now `context-stats`.
|
|
279
|
+
|
|
280
|
+
</details>
|
|
281
|
+
|
|
282
|
+
<details>
|
|
283
|
+
<summary><strong>Documentation</strong></summary>
|
|
284
|
+
|
|
285
|
+
- [Installation Guide](docs/installation.md) - Platform-specific setup (shell, pip, npm)
|
|
286
|
+
- [Context Stats Guide](docs/context-stats.md) - Detailed CLI usage guide
|
|
287
|
+
- [Configuration Options](docs/configuration.md) - All settings explained
|
|
288
|
+
- [Available Scripts](docs/scripts.md) - Script variants and features
|
|
289
|
+
- [Model Intelligence](docs/MODEL_INTELLIGENCE.md) - MI formula, per-model profiles, benchmark data
|
|
290
|
+
- [Architecture](docs/ARCHITECTURE.md) - System design and components
|
|
291
|
+
- [CSV Format](docs/CSV_FORMAT.md) - State file field specification
|
|
292
|
+
- [Development](docs/DEVELOPMENT.md) - Dev setup, testing, and debugging
|
|
293
|
+
- [Deployment](docs/DEPLOYMENT.md) - Publishing and release process
|
|
294
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
|
|
295
|
+
- [Changelog](CHANGELOG.md) - Version history
|
|
296
|
+
|
|
297
|
+
</details>
|
|
298
|
+
|
|
299
|
+
<details>
|
|
300
|
+
<summary><strong>Contributing</strong></summary>
|
|
301
|
+
|
|
302
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on the development setup, branching strategy, and PR process.
|
|
303
|
+
|
|
304
|
+
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).
|
|
305
|
+
|
|
306
|
+
</details>
|
|
307
|
+
|
|
308
|
+
<details>
|
|
309
|
+
<summary><strong>How It Works (Architecture)</strong></summary>
|
|
310
|
+
|
|
311
|
+
Context Stats hooks into Claude Code's status line feature to track token usage across your sessions. The Python and Node.js statusline scripts write state data to local CSV files, which the context-stats CLI reads to render live graphs. Data is stored locally in `~/.claude/statusline/` and never sent anywhere.
|
|
312
|
+
|
|
313
|
+
The statusline is implemented in three languages (Bash, Python, Node.js) so you can choose whichever runtime you have available. Claude Code invokes the statusline script via stdin JSON pipe — any implementation that reads JSON from stdin and writes formatted text to stdout works.
|
|
314
|
+
|
|
315
|
+
</details>
|
|
316
|
+
|
|
317
|
+
## Related
|
|
318
|
+
|
|
319
|
+
- [Claude Code Documentation](https://docs.anthropic.com/en/docs/claude-code)
|
|
320
|
+
- [Blog: Building this project](https://medium.com/@luongnv89/closing-the-gap-between-mvp-and-production-with-feature-dev-an-official-plugin-from-anthropic-444e2f00a0ad)
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT
|
package/README.md
CHANGED
|
@@ -1,93 +1,306 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="assets/logo/logo-full.svg" alt="cc-context-stats" width="320"/>
|
|
3
3
|
|
|
4
|
-
<
|
|
4
|
+
<h1>Stop Shipping from a Half-Blind Model</h1>
|
|
5
5
|
|
|
6
|
-
<p>Real-time
|
|
6
|
+
<p><strong>Real-time model intelligence monitoring for Claude Code.</strong><br/>Know exactly when your model is at peak quality — and when it's time for a fresh session.</p>
|
|
7
7
|
|
|
8
|
-
[](https://pypi.org/project/cc-context-stats/)
|
|
9
|
+
[](https://www.npmjs.com/package/cc-context-stats)
|
|
10
10
|
[](https://pypi.org/project/cc-context-stats/)
|
|
11
11
|
[](https://www.npmjs.com/package/cc-context-stats)
|
|
12
|
+
[](https://github.com/luongnv89/cc-context-stats)
|
|
12
13
|
[](https://opensource.org/licenses/MIT)
|
|
13
14
|
|
|
15
|
+
[**Get Started in 60 Seconds →**](#installation)
|
|
16
|
+
|
|
14
17
|
</div>
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
---
|
|
17
20
|
|
|
18
|
-

|
|
19
22
|
|
|
20
|
-
##
|
|
23
|
+
## The Problem
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
You're deep into a Claude Code session — refactoring, debugging, shipping. Everything feels fine. But behind the scenes:
|
|
23
26
|
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **Make informed decisions** - Know when to start a fresh session
|
|
27
|
+
- **Your model is getting dumber and you can't see it.** Research shows LLM retrieval accuracy drops as the context window fills. Claude starts missing details, hallucinating references, and losing track of your codebase — silently.
|
|
28
|
+
- **You don't know when to start fresh.** Is 50% context usage safe? 70%? It depends on the model. Opus holds quality longer than Sonnet, which degrades faster than Haiku. Without data, you're guessing.
|
|
29
|
+
- **Wasted sessions cost real money.** Pushing through a degraded context means more back-and-forth, more corrections, more tokens burned on worse output. You pay more for less.
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
You can't fix what you can't measure.
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
| ------------------- | ------------ | -------- | --------------------------------------------- |
|
|
33
|
-
| 🟢 **Smart Zone** | < 40% | Optimal | Claude is performing at its best |
|
|
34
|
-
| 🟡 **Dumb Zone** | 40-80% | Degraded | Context getting full, Claude may miss details |
|
|
35
|
-
| 🔴 **Wrap Up Zone** | > 80% | Critical | Better to wrap up and start a new session |
|
|
33
|
+
## How cc-context-stats Fixes This
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
cc-context-stats gives you a **Model Intelligence (MI) score** — a single number from 1.000 to 0.000 that tells you how sharp your model is right now, calibrated from Anthropic's [MRCR v2 8-needle](https://docs.anthropic.com/) retrieval benchmark.
|
|
36
|
+
|
|
37
|
+
- **One glance, full picture** — MI score lives in your Claude Code status bar. Green means sharp. Yellow means degrading. Red means stop and start fresh.
|
|
38
|
+
- **Per-model awareness** — Opus (beta=1.8) retains quality longest. Sonnet (beta=1.5) is moderate. Haiku (beta=1.2) degrades earliest. MI reflects your actual model automatically.
|
|
39
|
+
- **Live dashboard** — ASCII graphs track context growth, MI degradation, and token I/O over time. Watch quality erode in real-time so you can make informed decisions.
|
|
40
|
+
- **Fully customizable** — Control the color of every element, toggle each component on/off, and use named colors or hex codes to match your terminal theme.
|
|
41
|
+
- **Context zones** — Five-state indicators tell you where you stand:
|
|
42
|
+
|
|
43
|
+
| Zone | Indicator | Color | What It Means |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| **Planning** | Plan | Green | Safe to plan and code |
|
|
46
|
+
| **Code-only** | Code | Yellow | Avoid starting new plans |
|
|
47
|
+
| **Dump zone** | Dump | Orange | Quality declining — finish up |
|
|
48
|
+
| **Hard limit** | ExDump | Dark red | Start a new session now |
|
|
49
|
+
| **Dead zone** | Dead | Gray | Nothing productive here |
|
|
50
|
+
|
|
51
|
+
[**Install and See Your MI Score →**](#installation)
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
```mermaid
|
|
56
|
+
graph LR
|
|
57
|
+
A["Claude Code<br/>sends JSON via stdin"] --> B["Statusline Script<br/>(Python / Node.js / Bash)"]
|
|
58
|
+
B --> C["Status Bar Output<br/>colored, fitted to terminal width"]
|
|
59
|
+
B --> D["CSV State File<br/>~/.claude/statusline/"]
|
|
60
|
+
D --> E["context-stats CLI<br/>live ASCII dashboard"]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
1. **Install** — One command: `pip install cc-context-stats` or `npm install -g cc-context-stats`
|
|
64
|
+
2. **Configure** — Add the statusline command to `~/.claude/settings.json` (two lines of JSON)
|
|
65
|
+
3. **Restart Claude Code** — MI score and context stats appear in your status bar immediately
|
|
66
|
+
4. **Monitor** — Run `context-stats <session_id>` for a live dashboard with graphs, zone status, and session summary
|
|
67
|
+
|
|
68
|
+
| Status Bar (green — model is sharp) | Status Bar (yellow — quality degrading) |
|
|
69
|
+
|:---:|:---:|
|
|
70
|
+
|  |  |
|
|
71
|
+
|
|
72
|
+
| Delta Graph | Cumulative Graph |
|
|
73
|
+
|:---:|:---:|
|
|
74
|
+
|  |  |
|
|
75
|
+
|
|
76
|
+
[**See Full CLI Options →**](#context-stats-cli)
|
|
77
|
+
|
|
78
|
+
## Customization
|
|
79
|
+
|
|
80
|
+
Every element in the status line can be individually colored and toggled. Configuration lives in `~/.claude/statusline.conf` (created automatically on first run).
|
|
81
|
+
|
|
82
|
+
### Status Line Anatomy
|
|
83
|
+
|
|
84
|
+
The status line is assembled left-to-right in **priority order** — when the terminal is too narrow, lower-priority elements on the right are dropped first:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
project-dir | main [3] | 64,000 free (32.0%) | Plan | MI:0.918 | +2,500 | Opus 4.6 (1M context) | session_id
|
|
88
|
+
─────┬──── ───┬──── ────────┬────────── ──┬── ───┬──── ──┬─── ──────────┬────────── ────┬──────
|
|
89
|
+
│ │ │ │ │ │ │ │
|
|
90
|
+
project_name branch_name context_length zone mi_score separator separator separator
|
|
91
|
+
(cyan) (green) (bold_white) (auto) (yellow) (dim) (dim) (dim)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Position | Element | Config Key | Default Color | What It Shows |
|
|
95
|
+
|:---:|---|---|---|---|
|
|
96
|
+
| 1 | Project directory | `color_project_name` | cyan | Current working directory |
|
|
97
|
+
| 2 | Git branch + changes | `color_branch_name` | green | Branch name and `[N]` uncommitted changes |
|
|
98
|
+
| 3 | Context remaining | `color_context_length` | bold_white | Tokens free + usage percentage |
|
|
99
|
+
| 4 | Zone indicator | `color_zone` | auto (zone color) | Plan / Code / Dump / ExDump / Dead |
|
|
100
|
+
| 5 | MI score | `color_mi_score` | yellow | Model Intelligence: `MI:0.918` |
|
|
101
|
+
| 6 | Token delta | `color_separator` | dim | Change since last refresh: `+2,500` |
|
|
102
|
+
| 7 | Model name | `color_separator` | dim | `Opus 4.6 (1M context)` |
|
|
103
|
+
| 8 | Session ID | `color_separator` | dim | Session identifier |
|
|
104
|
+
|
|
105
|
+
Elements 6-8 share `color_separator` because they are structural/secondary information. The most critical data (project, branch, context, zone, MI) each have their own dedicated color key.
|
|
38
106
|
|
|
39
|
-
###
|
|
107
|
+
### Per-Element Color Control
|
|
40
108
|
|
|
41
|
-
|
|
109
|
+
Override any element's color independently. Per-property keys take precedence over base color slots.
|
|
42
110
|
|
|
43
111
|
```bash
|
|
44
|
-
|
|
112
|
+
# ~/.claude/statusline.conf
|
|
113
|
+
|
|
114
|
+
# Each element has its own color key
|
|
115
|
+
color_context_length=bold_white # The most critical info — tokens remaining
|
|
116
|
+
color_project_name=cyan # Which project you're working in
|
|
117
|
+
color_branch_name=green # Git branch at a glance
|
|
118
|
+
color_mi_score=yellow # Model Intelligence score
|
|
119
|
+
color_zone=default # Zone indicator (uses zone's own color by default)
|
|
120
|
+
color_separator=dim # Model name, delta, session ID
|
|
45
121
|
```
|
|
46
122
|
|
|
47
|
-
###
|
|
123
|
+
### Base Color Slots (MI-Aware)
|
|
124
|
+
|
|
125
|
+
These control the automatic MI-based coloring of context tokens and act as fallbacks for per-property keys:
|
|
48
126
|
|
|
49
127
|
```bash
|
|
50
|
-
|
|
128
|
+
# Base MI color thresholds
|
|
129
|
+
color_green=#7dcfff # Used when MI > 0.70 (model is sharp)
|
|
130
|
+
color_yellow=bright_yellow # Used when MI 0.40–0.70 (quality degrading)
|
|
131
|
+
color_red=#f7768e # Used when MI < 0.40 (start a new session)
|
|
132
|
+
|
|
133
|
+
# Legacy element fallbacks (used if per-property key is not set)
|
|
134
|
+
color_blue=bright_blue # Fallback for color_project_name
|
|
135
|
+
color_magenta=#bb9af7 # Fallback for color_branch_name
|
|
136
|
+
color_cyan=bright_cyan # Git change count [N]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Color Resolution Order
|
|
140
|
+
|
|
141
|
+
When rendering each element, the system checks colors in this order:
|
|
142
|
+
|
|
143
|
+
```mermaid
|
|
144
|
+
graph TD
|
|
145
|
+
A["Per-property key set?<br/>(e.g. color_project_name)"] -->|Yes| B["Use per-property color"]
|
|
146
|
+
A -->|No| C["Base color key set?<br/>(e.g. color_blue)"]
|
|
147
|
+
C -->|Yes| D["Use base color"]
|
|
148
|
+
C -->|No| E["Use built-in default"]
|
|
51
149
|
```
|
|
52
150
|
|
|
53
|
-
|
|
151
|
+
For example, `color_project_name` falls back to `color_blue`, which falls back to the built-in cyan.
|
|
152
|
+
|
|
153
|
+
### Supported Color Values
|
|
154
|
+
|
|
155
|
+
| Format | Examples | Notes |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| Named colors | `red`, `green`, `cyan`, `white` | Standard 16-color terminal palette |
|
|
158
|
+
| Bright variants | `bright_red`, `bright_green`, `bright_cyan` | High-intensity versions |
|
|
159
|
+
| Special | `bold_white`, `dim` | Weight/opacity modifiers |
|
|
160
|
+
| Hex codes | `#7dcfff`, `#f7768e`, `#bb9af7` | 24-bit truecolor (requires terminal support) |
|
|
161
|
+
|
|
162
|
+
Full named color list: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `bright_black`, `bright_red`, `bright_green`, `bright_yellow`, `bright_blue`, `bright_magenta`, `bright_cyan`, `bright_white`, `bold_white`, `dim`
|
|
163
|
+
|
|
164
|
+
Unrecognized values are ignored with a warning to stderr. Omitted keys use defaults.
|
|
165
|
+
|
|
166
|
+
### Toggle Elements On/Off
|
|
167
|
+
|
|
168
|
+
Control which elements appear in the status line:
|
|
54
169
|
|
|
55
170
|
```bash
|
|
56
|
-
|
|
171
|
+
# ~/.claude/statusline.conf
|
|
172
|
+
|
|
173
|
+
show_delta=true # Show token delta [+2,500] (default: true)
|
|
174
|
+
show_session=true # Show session ID (default: true)
|
|
175
|
+
show_mi=false # Show MI score (default: false — enable it!)
|
|
176
|
+
token_detail=true # Exact counts "64,000" vs abbreviated "64.0k" (default: true)
|
|
177
|
+
autocompact=true # Factor in autocompact buffer (default: true)
|
|
178
|
+
reduced_motion=false # Disable text animations (default: false)
|
|
57
179
|
```
|
|
58
180
|
|
|
59
|
-
###
|
|
181
|
+
### Example Configurations
|
|
182
|
+
|
|
183
|
+
**Tokyo Night theme** — dark purple/blue palette:
|
|
60
184
|
|
|
61
185
|
```bash
|
|
62
|
-
|
|
186
|
+
# ~/.claude/statusline.conf
|
|
187
|
+
color_green=#7dcfff
|
|
188
|
+
color_yellow=#e0af68
|
|
189
|
+
color_red=#f7768e
|
|
190
|
+
color_project_name=#7aa2f7
|
|
191
|
+
color_branch_name=#bb9af7
|
|
192
|
+
color_context_length=bold_white
|
|
193
|
+
color_mi_score=#e0af68
|
|
194
|
+
color_separator=dim
|
|
195
|
+
show_mi=true
|
|
63
196
|
```
|
|
64
197
|
|
|
65
|
-
|
|
198
|
+
**High contrast** — maximum readability:
|
|
66
199
|
|
|
67
200
|
```bash
|
|
68
|
-
|
|
201
|
+
# ~/.claude/statusline.conf
|
|
202
|
+
color_project_name=bright_white
|
|
203
|
+
color_branch_name=bright_green
|
|
204
|
+
color_context_length=bold_white
|
|
205
|
+
color_mi_score=bright_yellow
|
|
206
|
+
color_separator=bright_black
|
|
207
|
+
color_green=bright_green
|
|
208
|
+
color_yellow=bright_yellow
|
|
209
|
+
color_red=bright_red
|
|
210
|
+
show_mi=true
|
|
69
211
|
```
|
|
70
212
|
|
|
71
|
-
|
|
213
|
+
**Minimal** — context and MI only, muted colors:
|
|
72
214
|
|
|
73
|
-
|
|
215
|
+
```bash
|
|
216
|
+
# ~/.claude/statusline.conf
|
|
217
|
+
show_delta=false
|
|
218
|
+
show_session=false
|
|
219
|
+
show_mi=true
|
|
220
|
+
color_project_name=dim
|
|
221
|
+
color_branch_name=dim
|
|
222
|
+
color_context_length=bold_white
|
|
223
|
+
color_mi_score=yellow
|
|
224
|
+
color_separator=dim
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Monochrome** — no color, just structure:
|
|
74
228
|
|
|
75
229
|
```bash
|
|
76
|
-
|
|
230
|
+
# ~/.claude/statusline.conf
|
|
231
|
+
color_project_name=white
|
|
232
|
+
color_branch_name=white
|
|
233
|
+
color_context_length=bold_white
|
|
234
|
+
color_mi_score=white
|
|
235
|
+
color_separator=dim
|
|
236
|
+
color_green=white
|
|
237
|
+
color_yellow=white
|
|
238
|
+
color_red=white
|
|
77
239
|
```
|
|
78
240
|
|
|
79
|
-
|
|
241
|
+
### MI Curve Customization
|
|
242
|
+
|
|
243
|
+
The MI degradation curve is model-specific by default. Override it for all models with `mi_curve_beta`:
|
|
80
244
|
|
|
81
245
|
```bash
|
|
82
|
-
|
|
246
|
+
# ~/.claude/statusline.conf
|
|
247
|
+
mi_curve_beta=0 # Auto-detect (default): Opus=1.8, Sonnet=1.5, Haiku=1.2
|
|
248
|
+
mi_curve_beta=1.5 # Force Sonnet-like curve for all models
|
|
249
|
+
mi_curve_beta=2.0 # More optimistic — quality retained longer
|
|
250
|
+
mi_curve_beta=1.0 # More pessimistic — warns earlier
|
|
83
251
|
```
|
|
84
252
|
|
|
85
|
-
|
|
253
|
+
Higher beta = the model retains quality longer before degrading. Lower beta = earlier warnings.
|
|
254
|
+
|
|
255
|
+
## Model Intelligence — The Science
|
|
256
|
+
|
|
257
|
+
MI is derived from `MI(u) = max(0, 1 - u^beta)` where `u` is context utilization and `beta` is a model-specific degradation rate calibrated against Anthropic's MRCR v2 8-needle long-context retrieval benchmark.
|
|
86
258
|
|
|
87
|
-
|
|
259
|
+
| Model | Beta | MI at 50% Context | MI at 75% Context | When to Worry |
|
|
260
|
+
|-------|------|-----------|-----------|---------------|
|
|
261
|
+
| Opus | 1.8 | 0.713 | 0.404 | ~60% used |
|
|
262
|
+
| Sonnet| 1.5 | 0.646 | 0.350 | ~50% used |
|
|
263
|
+
| Haiku | 1.2 | 0.565 | 0.292 | ~45% used |
|
|
264
|
+
|
|
265
|
+
The model is auto-detected from your session. See [Model Intelligence docs](docs/MODEL_INTELLIGENCE.md) for the full formula and benchmark data.
|
|
266
|
+
|
|
267
|
+
## Installation
|
|
268
|
+
|
|
269
|
+
### Shell Script (quickest)
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
curl -fsSL https://raw.githubusercontent.com/luongnv89/cc-context-stats/main/install.sh | bash
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### npm
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npm install -g cc-context-stats
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Python
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
pip install cc-context-stats
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Or with uv:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
uv pip install cc-context-stats
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Verify Installation
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
curl -fsSL https://raw.githubusercontent.com/luongnv89/cc-context-stats/main/scripts/check-install.sh | bash
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Quick Start
|
|
88
300
|
|
|
89
301
|
Add to `~/.claude/settings.json`:
|
|
90
302
|
|
|
303
|
+
**pip or npm install:**
|
|
91
304
|
```json
|
|
92
305
|
{
|
|
93
306
|
"statusLine": {
|
|
@@ -97,30 +310,50 @@ Add to `~/.claude/settings.json`:
|
|
|
97
310
|
}
|
|
98
311
|
```
|
|
99
312
|
|
|
100
|
-
|
|
313
|
+
**Shell script install (`install.sh`):**
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"statusLine": {
|
|
317
|
+
"type": "command",
|
|
318
|
+
"command": "~/.claude/statusline.sh"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
101
322
|
|
|
102
|
-
|
|
323
|
+
Restart Claude Code. MI score and context stats appear in your status bar immediately.
|
|
103
324
|
|
|
104
|
-
|
|
325
|
+
### Real-Time Dashboard
|
|
326
|
+
|
|
327
|
+
Get your session ID from the status line (the last part after the pipe `|`), then:
|
|
105
328
|
|
|
106
329
|
```bash
|
|
107
330
|
context-stats <session_id>
|
|
108
331
|
```
|
|
109
332
|
|
|
110
|
-
For example:
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
context-stats abc123def-456-789
|
|
114
333
|
```
|
|
334
|
+
Context Stats (my-project • abc123def)
|
|
115
335
|
|
|
116
|
-
|
|
336
|
+
Context Growth Per Interaction
|
|
337
|
+
Max: 4,787 Min: 0 Points: 254
|
|
338
|
+
...graph...
|
|
117
339
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
340
|
+
Session Summary
|
|
341
|
+
----------------------------------------------------------------------------
|
|
342
|
+
Context Remaining: 43,038/200,000 (21%)
|
|
343
|
+
>>> DUMB ZONE <<< (You are in the dumb zone - Dex Horthy says so)
|
|
344
|
+
Model Intelligence: 0.646 (Context pressure building, consider wrapping up)
|
|
345
|
+
Context: 79% used
|
|
346
|
+
|
|
347
|
+
Last Growth: +2,500
|
|
348
|
+
Input Tokens: 1,234
|
|
349
|
+
Output Tokens: 567
|
|
350
|
+
Lines Changed: +45 / -12
|
|
351
|
+
Total Cost: $0.1234
|
|
352
|
+
Model: claude-sonnet-4-6
|
|
353
|
+
Session Duration: 2h 29m
|
|
354
|
+
```
|
|
122
355
|
|
|
123
|
-
|
|
356
|
+
[**See All Graph Types and Options →**](#context-stats-cli)
|
|
124
357
|
|
|
125
358
|
## Context Stats CLI
|
|
126
359
|
|
|
@@ -130,76 +363,71 @@ context-stats -w 5 # Custom refresh interval (5 seconds)
|
|
|
130
363
|
context-stats --no-watch # Show once and exit
|
|
131
364
|
context-stats --type cumulative # Show cumulative context usage
|
|
132
365
|
context-stats --type both # Show both graphs
|
|
133
|
-
context-stats --type
|
|
366
|
+
context-stats --type mi # Model Intelligence over time
|
|
367
|
+
context-stats --type all # Show all graphs including I/O and MI
|
|
134
368
|
context-stats <session_id> # View specific session
|
|
135
369
|
context-stats explain # Diagnostic dump (pipe JSON to stdin)
|
|
136
370
|
context-stats --version # Show version
|
|
137
371
|
```
|
|
138
372
|
|
|
139
|
-
|
|
373
|
+
## FAQ
|
|
140
374
|
|
|
141
|
-
|
|
142
|
-
|
|
375
|
+
**Is it free?**
|
|
376
|
+
Yes. MIT licensed, zero dependencies, free forever. [See the license](LICENSE).
|
|
143
377
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
...graph...
|
|
378
|
+
**Does it send my data anywhere?**
|
|
379
|
+
No. All data stays local in `~/.claude/statusline/`. No network requests, no telemetry, no API keys required.
|
|
147
380
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Context Remaining: 43,038/200,000 (21%)
|
|
151
|
-
>>> DUMB ZONE <<< (You are in the dumb zone - Dex Horthy says so)
|
|
381
|
+
**Is it actively maintained?**
|
|
382
|
+
Very. 11 releases since January 2025, with MI per-model profiles, configurable colors, state rotation, and cross-implementation parity tests all shipped in the last few months.
|
|
152
383
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
384
|
+
**How does it compare to just watching the context counter?**
|
|
385
|
+
The raw context counter tells you how full the window is. MI tells you how much quality you've lost — which depends on the model. 50% context on Opus (MI: 0.713) is fine. 50% on Haiku (MI: 0.565) means you should start wrapping up. cc-context-stats gives you the nuance.
|
|
386
|
+
|
|
387
|
+
**Can I use it with Opus, Sonnet, and Haiku?**
|
|
388
|
+
Yes. MI auto-detects your model and applies the correct degradation curve. Each model has a calibrated beta value from benchmark data.
|
|
389
|
+
|
|
390
|
+
**What runtimes does it support?**
|
|
391
|
+
Python (pip), Node.js (npm), or pure Bash. The statusline scripts are implemented in all three languages so you can use whichever runtime you have available.
|
|
161
392
|
|
|
162
|
-
|
|
393
|
+
**How do I customize colors?**
|
|
394
|
+
Create `~/.claude/statusline.conf` with named colors or hex codes. See the [Customization section](#customization) above or the [full configuration docs](docs/configuration.md).
|
|
163
395
|
|
|
164
|
-
|
|
396
|
+
## Start Shipping with Confidence
|
|
165
397
|
|
|
166
|
-
|
|
398
|
+
You wouldn't deploy without monitoring your servers. Don't code without monitoring your model.
|
|
167
399
|
|
|
168
|
-
|
|
169
|
-
| --------- | ----------------------------------------- |
|
|
170
|
-
| Model | Current Claude model |
|
|
171
|
-
| Context | Tokens used / remaining with color coding |
|
|
172
|
-
| Delta | Token change since last update |
|
|
173
|
-
| Git | Branch name and uncommitted changes |
|
|
174
|
-
| Session | Session ID for correlation |
|
|
400
|
+
cc-context-stats is MIT licensed, has zero dependencies, installs in one command, and works with any Claude Code setup. If you don't like it, `pip uninstall cc-context-stats` and it's gone.
|
|
175
401
|
|
|
176
|
-
|
|
402
|
+
[**Install cc-context-stats Now →**](#installation)
|
|
177
403
|
|
|
178
|
-
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
<details>
|
|
407
|
+
<summary><strong>Migration from cc-statusline</strong></summary>
|
|
408
|
+
|
|
409
|
+
If you were using the previous `cc-statusline` package:
|
|
179
410
|
|
|
180
411
|
```bash
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
show_session=true # Show session ID
|
|
184
|
-
autocompact=true # Show autocompact buffer indicator
|
|
185
|
-
reduced_motion=false # Disable animations for accessibility
|
|
412
|
+
pip uninstall cc-statusline
|
|
413
|
+
```
|
|
186
414
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
color_red=#f7768e
|
|
190
|
-
color_yellow=bright_yellow
|
|
415
|
+
```bash
|
|
416
|
+
pip install cc-context-stats
|
|
191
417
|
```
|
|
192
418
|
|
|
193
|
-
|
|
419
|
+
The `claude-statusline` command still works. The main change is `token-graph` is now `context-stats`.
|
|
194
420
|
|
|
195
|
-
|
|
421
|
+
</details>
|
|
196
422
|
|
|
197
|
-
|
|
423
|
+
<details>
|
|
424
|
+
<summary><strong>Documentation</strong></summary>
|
|
198
425
|
|
|
199
426
|
- [Installation Guide](docs/installation.md) - Platform-specific setup (shell, pip, npm)
|
|
200
427
|
- [Context Stats Guide](docs/context-stats.md) - Detailed CLI usage guide
|
|
201
428
|
- [Configuration Options](docs/configuration.md) - All settings explained
|
|
202
429
|
- [Available Scripts](docs/scripts.md) - Script variants and features
|
|
430
|
+
- [Model Intelligence](docs/MODEL_INTELLIGENCE.md) - MI formula, per-model profiles, benchmark data
|
|
203
431
|
- [Architecture](docs/ARCHITECTURE.md) - System design and components
|
|
204
432
|
- [CSV Format](docs/CSV_FORMAT.md) - State file field specification
|
|
205
433
|
- [Development](docs/DEVELOPMENT.md) - Dev setup, testing, and debugging
|
|
@@ -207,22 +435,25 @@ Context Stats hooks into Claude Code's status line feature to track token usage
|
|
|
207
435
|
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
|
|
208
436
|
- [Changelog](CHANGELOG.md) - Version history
|
|
209
437
|
|
|
210
|
-
|
|
438
|
+
</details>
|
|
439
|
+
|
|
440
|
+
<details>
|
|
441
|
+
<summary><strong>Contributing</strong></summary>
|
|
211
442
|
|
|
212
443
|
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on the development setup, branching strategy, and PR process.
|
|
213
444
|
|
|
214
445
|
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).
|
|
215
446
|
|
|
216
|
-
|
|
447
|
+
</details>
|
|
217
448
|
|
|
218
|
-
|
|
449
|
+
<details>
|
|
450
|
+
<summary><strong>How It Works (Architecture)</strong></summary>
|
|
219
451
|
|
|
220
|
-
|
|
221
|
-
pip uninstall cc-statusline
|
|
222
|
-
pip install cc-context-stats
|
|
223
|
-
```
|
|
452
|
+
Context Stats hooks into Claude Code's status line feature to track token usage across your sessions. The Python and Node.js statusline scripts write state data to local CSV files, which the context-stats CLI reads to render live graphs. Data is stored locally in `~/.claude/statusline/` and never sent anywhere.
|
|
224
453
|
|
|
225
|
-
The
|
|
454
|
+
The statusline is implemented in three languages (Bash, Python, Node.js) so you can choose whichever runtime you have available. Claude Code invokes the statusline script via stdin JSON pipe — any implementation that reads JSON from stdin and writes formatted text to stdout works.
|
|
455
|
+
|
|
456
|
+
</details>
|
|
226
457
|
|
|
227
458
|
## Related
|
|
228
459
|
|
package/package.json
CHANGED
package/scripts/context-stats.sh
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
# === CONFIGURATION ===
|
|
24
24
|
# shellcheck disable=SC2034
|
|
25
|
-
VERSION="1.
|
|
25
|
+
VERSION="1.11.1"
|
|
26
26
|
COMMIT_HASH="dev" # Will be replaced during installation
|
|
27
27
|
STATE_DIR=~/.claude/statusline
|
|
28
28
|
CONFIG_FILE=~/.claude/statusline.conf
|
|
@@ -82,6 +82,7 @@ OPTIONS:
|
|
|
82
82
|
-w [interval] Set refresh interval in seconds (default: 2)
|
|
83
83
|
--no-watch Show graphs once and exit (disable live monitoring)
|
|
84
84
|
--no-color Disable color output
|
|
85
|
+
--version, -V Show version and exit
|
|
85
86
|
--help Show this help message
|
|
86
87
|
|
|
87
88
|
NOTE:
|
|
@@ -886,6 +887,10 @@ parse_args() {
|
|
|
886
887
|
show_help
|
|
887
888
|
exit 0
|
|
888
889
|
;;
|
|
890
|
+
--version | -V)
|
|
891
|
+
echo "cc-context-stats v${VERSION} (${COMMIT_HASH})"
|
|
892
|
+
exit 0
|
|
893
|
+
;;
|
|
889
894
|
--no-color)
|
|
890
895
|
COLOR_ENABLED=false
|
|
891
896
|
shift
|
package/scripts/statusline.js
CHANGED
|
@@ -36,26 +36,41 @@ const os = require('os');
|
|
|
36
36
|
const ROTATION_THRESHOLD = 10000;
|
|
37
37
|
const ROTATION_KEEP = 5000;
|
|
38
38
|
|
|
39
|
-
// Model Intelligence
|
|
40
|
-
const MI_GREEN_THRESHOLD = 0.
|
|
41
|
-
const MI_YELLOW_THRESHOLD = 0.
|
|
39
|
+
// Model Intelligence color thresholds
|
|
40
|
+
const MI_GREEN_THRESHOLD = 0.9;
|
|
41
|
+
const MI_YELLOW_THRESHOLD = 0.8;
|
|
42
|
+
const MI_CONTEXT_YELLOW = 0.4; // 40% context used
|
|
43
|
+
const MI_CONTEXT_RED = 0.8; // 80% context used
|
|
42
44
|
|
|
43
45
|
// Per-model degradation profiles: beta controls curve shape
|
|
44
46
|
// Higher beta = quality retained longer (degradation happens later)
|
|
45
47
|
const MODEL_PROFILES = {
|
|
46
|
-
opus:
|
|
47
|
-
sonnet:
|
|
48
|
-
haiku:
|
|
48
|
+
opus: 1.8,
|
|
49
|
+
sonnet: 1.5,
|
|
50
|
+
haiku: 1.2,
|
|
49
51
|
default: 1.5,
|
|
50
52
|
};
|
|
51
53
|
|
|
54
|
+
// Zone indicator thresholds
|
|
55
|
+
const LARGE_MODEL_THRESHOLD = 500000; // >= 500k context = 1M-class model
|
|
56
|
+
const ZONE_1M_P_MAX = 70000; // P zone: < 70k used
|
|
57
|
+
const ZONE_1M_C_MAX = 100000; // C zone: 70k–100k used
|
|
58
|
+
const ZONE_1M_D_MAX = 250000; // D zone: 100k–250k used
|
|
59
|
+
const ZONE_1M_X_MAX = 275000; // X zone: 250k–275k used; Z zone: >= 275k
|
|
60
|
+
const ZONE_STD_DUMP_ZONE = 0.4;
|
|
61
|
+
const ZONE_STD_WARN_BUFFER = 30000;
|
|
62
|
+
const ZONE_STD_HARD_LIMIT = 0.7;
|
|
63
|
+
const ZONE_STD_DEAD_ZONE = 0.75;
|
|
64
|
+
|
|
52
65
|
/**
|
|
53
66
|
* Match model_id to degradation beta.
|
|
54
67
|
*/
|
|
55
68
|
function getModelProfile(modelId) {
|
|
56
69
|
const lower = (modelId || '').toLowerCase();
|
|
57
70
|
for (const family of ['opus', 'sonnet', 'haiku']) {
|
|
58
|
-
if (lower.includes(family))
|
|
71
|
+
if (lower.includes(family)) {
|
|
72
|
+
return MODEL_PROFILES[family];
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
75
|
return MODEL_PROFILES.default;
|
|
61
76
|
}
|
|
@@ -72,22 +87,98 @@ function computeMI(usedTokens, contextWindowSize, modelId, betaOverride) {
|
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
const betaFromProfile = getModelProfile(modelId || '');
|
|
75
|
-
const beta =
|
|
90
|
+
const beta = betaOverride && betaOverride > 0 ? betaOverride : betaFromProfile;
|
|
76
91
|
|
|
77
92
|
const u = usedTokens / contextWindowSize;
|
|
78
|
-
if (u <= 0)
|
|
93
|
+
if (u <= 0) {
|
|
94
|
+
return { mi: 1.0 };
|
|
95
|
+
}
|
|
79
96
|
|
|
80
97
|
const mi = Math.max(0, 1 - Math.pow(u, beta));
|
|
81
98
|
return { mi };
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
/**
|
|
85
|
-
* Return ANSI color code for MI score.
|
|
102
|
+
* Return ANSI color code for MI score considering both MI and context utilization.
|
|
103
|
+
*/
|
|
104
|
+
function getMIColor(mi, utilization, greenColor, yellowColor, redColor) {
|
|
105
|
+
if (mi <= MI_YELLOW_THRESHOLD || utilization >= MI_CONTEXT_RED) {
|
|
106
|
+
return redColor || RED;
|
|
107
|
+
}
|
|
108
|
+
if (mi < MI_GREEN_THRESHOLD || utilization >= MI_CONTEXT_YELLOW) {
|
|
109
|
+
return yellowColor || YELLOW;
|
|
110
|
+
}
|
|
111
|
+
return greenColor || GREEN;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Determine context zone indicator (P/C/D/X/Z) based on token usage.
|
|
116
|
+
* Returns { zone, colorName }.
|
|
117
|
+
*/
|
|
118
|
+
function getContextZone(usedTokens, contextWindowSize) {
|
|
119
|
+
if (contextWindowSize === 0) {
|
|
120
|
+
return { zone: 'Plan', colorName: 'green' };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const isLarge = contextWindowSize >= LARGE_MODEL_THRESHOLD;
|
|
124
|
+
|
|
125
|
+
if (isLarge) {
|
|
126
|
+
if (usedTokens < ZONE_1M_P_MAX) {
|
|
127
|
+
return { zone: 'Plan', colorName: 'green' };
|
|
128
|
+
}
|
|
129
|
+
if (usedTokens < ZONE_1M_C_MAX) {
|
|
130
|
+
return { zone: 'Code', colorName: 'yellow' };
|
|
131
|
+
}
|
|
132
|
+
if (usedTokens < ZONE_1M_D_MAX) {
|
|
133
|
+
return { zone: 'Dump', colorName: 'orange' };
|
|
134
|
+
}
|
|
135
|
+
if (usedTokens < ZONE_1M_X_MAX) {
|
|
136
|
+
return { zone: 'ExDump', colorName: 'dark_red' };
|
|
137
|
+
}
|
|
138
|
+
return { zone: 'Dead', colorName: 'gray' };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Standard models (< 500k context)
|
|
142
|
+
const dumpZoneTokens = Math.floor(contextWindowSize * ZONE_STD_DUMP_ZONE);
|
|
143
|
+
const warnStart = Math.max(0, dumpZoneTokens - ZONE_STD_WARN_BUFFER);
|
|
144
|
+
const hardLimitTokens = Math.floor(contextWindowSize * ZONE_STD_HARD_LIMIT);
|
|
145
|
+
const deadZoneTokens = Math.floor(contextWindowSize * ZONE_STD_DEAD_ZONE);
|
|
146
|
+
|
|
147
|
+
if (usedTokens < warnStart) {
|
|
148
|
+
return { zone: 'Plan', colorName: 'green' };
|
|
149
|
+
}
|
|
150
|
+
if (usedTokens < dumpZoneTokens) {
|
|
151
|
+
return { zone: 'Code', colorName: 'yellow' };
|
|
152
|
+
}
|
|
153
|
+
if (usedTokens < hardLimitTokens) {
|
|
154
|
+
return { zone: 'Dump', colorName: 'orange' };
|
|
155
|
+
}
|
|
156
|
+
if (usedTokens < deadZoneTokens) {
|
|
157
|
+
return { zone: 'ExDump', colorName: 'dark_red' };
|
|
158
|
+
}
|
|
159
|
+
return { zone: 'Dead', colorName: 'gray' };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Map zone color name to ANSI escape code.
|
|
86
164
|
*/
|
|
87
|
-
function
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
165
|
+
function zoneAnsiColor(colorName) {
|
|
166
|
+
if (colorName === 'green') {
|
|
167
|
+
return GREEN;
|
|
168
|
+
}
|
|
169
|
+
if (colorName === 'yellow') {
|
|
170
|
+
return YELLOW;
|
|
171
|
+
}
|
|
172
|
+
if (colorName === 'orange') {
|
|
173
|
+
return '\x1b[38;2;255;165;0m';
|
|
174
|
+
}
|
|
175
|
+
if (colorName === 'dark_red') {
|
|
176
|
+
return '\x1b[38;2;139;0;0m';
|
|
177
|
+
}
|
|
178
|
+
if (colorName === 'gray') {
|
|
179
|
+
return '\x1b[0;90m';
|
|
180
|
+
}
|
|
181
|
+
return RESET;
|
|
91
182
|
}
|
|
92
183
|
|
|
93
184
|
/**
|
|
@@ -154,6 +245,8 @@ const COLOR_NAMES = {
|
|
|
154
245
|
bright_magenta: '\x1b[0;95m',
|
|
155
246
|
bright_cyan: '\x1b[0;96m',
|
|
156
247
|
bright_white: '\x1b[0;97m',
|
|
248
|
+
bold_white: '\x1b[1;97m',
|
|
249
|
+
dim: '\x1b[2m',
|
|
157
250
|
};
|
|
158
251
|
|
|
159
252
|
/**
|
|
@@ -182,6 +275,13 @@ const COLOR_CONFIG_KEYS = {
|
|
|
182
275
|
color_blue: 'blue',
|
|
183
276
|
color_magenta: 'magenta',
|
|
184
277
|
color_cyan: 'cyan',
|
|
278
|
+
// Per-property color keys
|
|
279
|
+
color_context_length: 'context_length',
|
|
280
|
+
color_project_name: 'project_name',
|
|
281
|
+
color_branch_name: 'branch_name',
|
|
282
|
+
color_mi_score: 'mi_score',
|
|
283
|
+
color_zone: 'zone',
|
|
284
|
+
color_separator: 'separator',
|
|
185
285
|
};
|
|
186
286
|
|
|
187
287
|
/**
|
|
@@ -290,7 +390,7 @@ function readConfig() {
|
|
|
290
390
|
showSession: true,
|
|
291
391
|
showIoTokens: true,
|
|
292
392
|
reducedMotion: false,
|
|
293
|
-
showMI:
|
|
393
|
+
showMI: false,
|
|
294
394
|
miCurveBeta: 0,
|
|
295
395
|
colors: {},
|
|
296
396
|
};
|
|
@@ -409,17 +509,23 @@ process.stdin.on('end', () => {
|
|
|
409
509
|
const cMagenta = c.magenta || MAGENTA;
|
|
410
510
|
const cCyan = c.cyan || CYAN;
|
|
411
511
|
|
|
412
|
-
//
|
|
413
|
-
|
|
512
|
+
// Per-property color defaults (highlighted key info)
|
|
513
|
+
// Falls back to old color keys for backward compatibility, then to new defaults
|
|
514
|
+
const cProjectName = c.project_name || (c.blue ? cBlue : CYAN);
|
|
515
|
+
const cBranchName = c.branch_name || (c.magenta ? cMagenta : GREEN);
|
|
516
|
+
const cSeparator = c.separator || DIM;
|
|
517
|
+
|
|
518
|
+
// Git info (use per-property branch color, fallback to green)
|
|
519
|
+
const gitInfo = getGitInfo(projectDir, cBranchName, cCyan);
|
|
414
520
|
|
|
415
521
|
// Extract session_id once for reuse
|
|
416
522
|
const sessionId = data.session_id;
|
|
417
523
|
|
|
418
524
|
// Context window calculation
|
|
419
525
|
let contextInfo = '';
|
|
420
|
-
let acInfo = '';
|
|
421
526
|
let deltaInfo = '';
|
|
422
527
|
let miInfo = '';
|
|
528
|
+
let zoneInfo = '';
|
|
423
529
|
let sessionInfo = '';
|
|
424
530
|
const showMI = config.showMI;
|
|
425
531
|
const miCurveBeta = config.miCurveBeta;
|
|
@@ -448,14 +554,9 @@ process.stdin.on('end', () => {
|
|
|
448
554
|
// Free tokens calculation depends on autocompact setting
|
|
449
555
|
let freeTokens;
|
|
450
556
|
if (autocompactEnabled) {
|
|
451
|
-
// When AC enabled: subtract buffer to show actual usable space
|
|
452
557
|
freeTokens = totalSize - usedTokens - autocompactBuffer;
|
|
453
|
-
const bufferK = Math.floor(autocompactBuffer / 1000);
|
|
454
|
-
acInfo = ` ${DIM}[AC:${bufferK}k]${RESET}`;
|
|
455
558
|
} else {
|
|
456
|
-
// When AC disabled: show full free space
|
|
457
559
|
freeTokens = totalSize - usedTokens;
|
|
458
|
-
acInfo = ` ${DIM}[AC:off]${RESET}`;
|
|
459
560
|
}
|
|
460
561
|
|
|
461
562
|
if (freeTokens < 0) {
|
|
@@ -464,24 +565,27 @@ process.stdin.on('end', () => {
|
|
|
464
565
|
|
|
465
566
|
// Calculate percentage with one decimal (relative to total size)
|
|
466
567
|
const freePct = (freeTokens * 100.0) / totalSize;
|
|
467
|
-
const freePctInt = Math.floor(freePct);
|
|
468
568
|
|
|
469
569
|
// Format tokens based on token_detail setting
|
|
470
570
|
const freeDisplay = tokenDetail
|
|
471
571
|
? freeTokens.toLocaleString('en-US')
|
|
472
572
|
: `${(freeTokens / 1000).toFixed(1)}k`;
|
|
473
573
|
|
|
474
|
-
// Color based on
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
ctxColor = cRed;
|
|
482
|
-
}
|
|
574
|
+
// Color based on MI thresholds (consistent with MI display)
|
|
575
|
+
const ctxUtil = totalSize > 0 ? usedTokens / totalSize : 0;
|
|
576
|
+
const ctxMI = computeMI(usedTokens, totalSize, modelId, miCurveBeta);
|
|
577
|
+
const ctxColor = getMIColor(ctxMI.mi, ctxUtil, cGreen, cYellow, cRed);
|
|
578
|
+
|
|
579
|
+
// Use per-property context_length color if configured, else MI-based color
|
|
580
|
+
const effectiveCtxColor = c.context_length || ctxColor;
|
|
483
581
|
|
|
484
|
-
contextInfo = ` | ${
|
|
582
|
+
contextInfo = ` | ${effectiveCtxColor}${freeDisplay} (${freePct.toFixed(1)}%)${RESET}`;
|
|
583
|
+
|
|
584
|
+
// Always show zone indicator
|
|
585
|
+
const zoneResult = getContextZone(usedTokens, totalSize);
|
|
586
|
+
// Use per-property zone color if configured, else dynamic zone color
|
|
587
|
+
const zoneAnsi = c.zone || zoneAnsiColor(zoneResult.colorName);
|
|
588
|
+
zoneInfo = ` | ${zoneAnsi}${zoneResult.zone}${RESET}`;
|
|
485
589
|
|
|
486
590
|
// Read previous entry if needed for delta OR MI
|
|
487
591
|
if (showDelta || showMI) {
|
|
@@ -550,15 +654,18 @@ process.stdin.on('end', () => {
|
|
|
550
654
|
const deltaDisplay = tokenDetail
|
|
551
655
|
? delta.toLocaleString('en-US')
|
|
552
656
|
: `${(delta / 1000).toFixed(1)}k`;
|
|
553
|
-
deltaInfo = ` ${
|
|
657
|
+
deltaInfo = ` | ${cSeparator}+${deltaDisplay}${RESET}`;
|
|
554
658
|
}
|
|
555
659
|
}
|
|
556
660
|
|
|
557
661
|
// Calculate and display MI score if enabled
|
|
558
662
|
if (showMI) {
|
|
559
663
|
const miResult = computeMI(usedTokens, totalSize, modelId, miCurveBeta);
|
|
560
|
-
const
|
|
561
|
-
|
|
664
|
+
const miUtil = totalSize > 0 ? usedTokens / totalSize : 0;
|
|
665
|
+
const miColor = getMIColor(miResult.mi, miUtil, cGreen, cYellow, cRed);
|
|
666
|
+
// Use per-property mi_score color if configured, else MI-based color
|
|
667
|
+
const effectiveMIColor = c.mi_score || miColor;
|
|
668
|
+
miInfo = ` | ${effectiveMIColor}MI:${miResult.mi.toFixed(3)}${RESET}`;
|
|
562
669
|
}
|
|
563
670
|
|
|
564
671
|
// Only append if context usage changed (avoid duplicates from multiple refreshes)
|
|
@@ -596,17 +703,25 @@ process.stdin.on('end', () => {
|
|
|
596
703
|
|
|
597
704
|
// Display session_id if enabled
|
|
598
705
|
if (showSession && sessionId) {
|
|
599
|
-
sessionInfo = ` ${
|
|
706
|
+
sessionInfo = ` | ${cSeparator}${sessionId}${RESET}`;
|
|
600
707
|
}
|
|
601
708
|
|
|
602
|
-
// Output:
|
|
603
|
-
|
|
709
|
+
// Output: dir | branch [n] | free (%) | zone | MI | +delta | [Model] session
|
|
710
|
+
// Model name is lowest priority — truncated first when terminal is narrow
|
|
711
|
+
const base = `${cProjectName}${dirName}${RESET}`;
|
|
712
|
+
const modelInfo = ` | ${cSeparator}${model}${RESET}`;
|
|
604
713
|
const maxWidth = getTerminalWidth();
|
|
605
|
-
const parts = [base, gitInfo, contextInfo,
|
|
714
|
+
const parts = [base, gitInfo, contextInfo, zoneInfo, miInfo, deltaInfo, modelInfo, sessionInfo];
|
|
606
715
|
console.log(fitToWidth(parts, maxWidth));
|
|
607
716
|
});
|
|
608
717
|
|
|
609
718
|
// Export for testing
|
|
610
719
|
if (typeof module !== 'undefined' && module.exports) {
|
|
611
|
-
module.exports = {
|
|
720
|
+
module.exports = {
|
|
721
|
+
maybeRotateStateFile,
|
|
722
|
+
ROTATION_THRESHOLD,
|
|
723
|
+
ROTATION_KEEP,
|
|
724
|
+
computeMI,
|
|
725
|
+
getContextZone,
|
|
726
|
+
};
|
|
612
727
|
}
|