cc-cockpit 0.2.0__tar.gz
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.
- cc_cockpit-0.2.0/LICENSE +21 -0
- cc_cockpit-0.2.0/PKG-INFO +203 -0
- cc_cockpit-0.2.0/README.md +180 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/PKG-INFO +203 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/SOURCES.txt +27 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/dependency_links.txt +1 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/entry_points.txt +2 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/requires.txt +4 -0
- cc_cockpit-0.2.0/cc_cockpit.egg-info/top_level.txt +1 -0
- cc_cockpit-0.2.0/cockpit/__init__.py +3 -0
- cc_cockpit-0.2.0/cockpit/__main__.py +5 -0
- cc_cockpit-0.2.0/cockpit/anchors.py +95 -0
- cc_cockpit-0.2.0/cockpit/calibration.py +62 -0
- cc_cockpit-0.2.0/cockpit/cli.py +228 -0
- cc_cockpit-0.2.0/cockpit/collector.py +188 -0
- cc_cockpit-0.2.0/cockpit/config.py +58 -0
- cc_cockpit-0.2.0/cockpit/desktop.py +68 -0
- cc_cockpit-0.2.0/cockpit/i18n.py +319 -0
- cc_cockpit-0.2.0/cockpit/icon.py +103 -0
- cc_cockpit-0.2.0/cockpit/panel.py +116 -0
- cc_cockpit-0.2.0/cockpit/pricing.py +71 -0
- cc_cockpit-0.2.0/cockpit/server.py +72 -0
- cc_cockpit-0.2.0/cockpit/sessions.py +86 -0
- cc_cockpit-0.2.0/cockpit/stats.py +335 -0
- cc_cockpit-0.2.0/cockpit/statusline.py +113 -0
- cc_cockpit-0.2.0/cockpit/tray.py +255 -0
- cc_cockpit-0.2.0/cockpit/web/index.html +294 -0
- cc_cockpit-0.2.0/pyproject.toml +47 -0
- cc_cockpit-0.2.0/setup.cfg +4 -0
cc_cockpit-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wallace Martins da Silva
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cc-cockpit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Claude Code usage panel for GNOME: tray indicator, local dashboard and terminal summary
|
|
5
|
+
Author: Wallace Martins da Silva
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/wallacemartinss/cc-cockpit
|
|
8
|
+
Project-URL: Issues, https://github.com/wallacemartinss/cc-cockpit/issues
|
|
9
|
+
Keywords: claude,claude-code,usage,gnome,tray,appindicator
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: X11 Applications :: GTK
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: tray
|
|
20
|
+
Requires-Dist: PyGObject>=3.42; extra == "tray"
|
|
21
|
+
Requires-Dist: pycairo>=1.20; extra == "tray"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# cc-cockpit
|
|
25
|
+
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
|
|
28
|
+
A Claude Code usage panel for GNOME: a tray indicator with a consumption ring,
|
|
29
|
+
a local dashboard and a terminal summary.
|
|
30
|
+
|
|
31
|
+
Everything is read from what Claude Code already writes under `~/.claude`. It
|
|
32
|
+
makes no network calls, reads no credentials and sends nothing anywhere.
|
|
33
|
+
|
|
34
|
+
The interface follows your OS language — English, Portuguese and Spanish are
|
|
35
|
+
bundled — and can be pinned in the config file or with `--lang`.
|
|
36
|
+
|
|
37
|
+
## What it shows
|
|
38
|
+
|
|
39
|
+
| | |
|
|
40
|
+
|---|---|
|
|
41
|
+
| **5h block** | how much the current rate-limit window has consumed, time to reset, hourly pace, projection to the end of the block, and how long until the reference ceiling. The window starts at the exact timestamp of its first request — not rounded to the hour — which is what makes the reset match what the CLI reports |
|
|
42
|
+
| **7 days / today / month** | rolling totals, as a percentage of your own historical peak |
|
|
43
|
+
| **Open sessions** | every live CLI instance: name, project, `busy`/`idle`, uptime, RAM, pid, and what that session has consumed |
|
|
44
|
+
| **Projects** | ranked by consumption across the whole history |
|
|
45
|
+
| **Blocks, days and hours** | time series showing when you actually spend |
|
|
46
|
+
| **Token mix** | input / output / cache write 5m / cache write 1h / cache read, with the cache hit rate |
|
|
47
|
+
| **Models, effort and subagents** | where the consumption really goes |
|
|
48
|
+
|
|
49
|
+
Usage is measured in **API-equivalent USD**: what those messages would cost on
|
|
50
|
+
the pay-as-you-go API. On a Pro/Max plan none of it is billed — the number works
|
|
51
|
+
as a weight unit for consumption and shows how much the plan returns.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
**Debian / Ubuntu** — the `.deb` pulls in the GTK dependencies by itself:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# from the latest release
|
|
59
|
+
sudo apt install ./cc-cockpit_0.2.0_all.deb
|
|
60
|
+
cc-cockpit setup
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Arch** — from the AUR:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
yay -S cc-cockpit # or: makepkg -si from packaging/PKGBUILD
|
|
67
|
+
cc-cockpit setup
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Any distribution** — pipx, reusing the system GTK bindings:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
sudo apt install python3-gi python3-cairo gir1.2-ayatanaappindicator3-0.1 # tray only
|
|
74
|
+
pipx install cc-cockpit --system-site-packages
|
|
75
|
+
cc-cockpit setup
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`--system-site-packages` is what lets the virtualenv see PyGObject and pycairo.
|
|
79
|
+
Without them the tray is unavailable, and the dashboard and `report` still work.
|
|
80
|
+
|
|
81
|
+
**From a checkout**:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/wallacemartinss/cc-cockpit
|
|
85
|
+
cd cc-cockpit && ./install.sh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`cc-cockpit setup` registers the GNOME autostart entry, captures the statusline
|
|
89
|
+
(see below), checks the tray dependencies and runs the first collection.
|
|
90
|
+
`cc-cockpit setup --remove` undoes the autostart entry.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cc-cockpit # tray + dashboard in the background
|
|
94
|
+
cc-cockpit report # terminal summary
|
|
95
|
+
cc-cockpit serve --open # dashboard only (http://127.0.0.1:8765)
|
|
96
|
+
cc-cockpit json # everything as JSON, for scripting
|
|
97
|
+
cc-cockpit collect # ingest new transcripts and exit
|
|
98
|
+
cc-cockpit config # config path and contents
|
|
99
|
+
cc-cockpit --lang es report
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## The real numbers, from the statusline
|
|
103
|
+
|
|
104
|
+
Two things cannot be derived from local transcripts:
|
|
105
|
+
|
|
106
|
+
1. **The limit belongs to the account, not to the CLI.** Whatever you consume in
|
|
107
|
+
the Claude app counts against the same window and leaves nothing on disk, so
|
|
108
|
+
a window can start before your first local request.
|
|
109
|
+
2. **The weekly limit is a fixed window** with its own reset time, not the
|
|
110
|
+
rolling 7 days a local reader would assume.
|
|
111
|
+
|
|
112
|
+
Claude Code pipes a JSON payload into the statusline command on every render,
|
|
113
|
+
and it carries exactly what the plan panel shows:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"rate_limits": {
|
|
117
|
+
"five_hour": {"used_percentage": 23, "resets_at": 1788800000},
|
|
118
|
+
"seven_day": {"used_percentage": 3, "resets_at": 1788790000}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Register the capture once — no credentials, no undocumented endpoint:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cc-cockpit statusline --install
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
It writes `statusLine` into `~/.claude/settings.json`, keeping a `.bak`. If you
|
|
129
|
+
already had one, it is chained rather than replaced, so its output still shows
|
|
130
|
+
in the CLI. The captured payload also carries the **context window percentage
|
|
131
|
+
per session**, which the dashboard shows next to each open session.
|
|
132
|
+
|
|
133
|
+
From then on the official percentage is the source of truth, and it reveals the
|
|
134
|
+
real ceiling — `local consumption ÷ official percentage` — so the currency
|
|
135
|
+
figures stay meaningful too.
|
|
136
|
+
|
|
137
|
+
### When there is no statusline data yet
|
|
138
|
+
|
|
139
|
+
Numbers fall back, in order of trust: **official** (statusline) → **anchored**
|
|
140
|
+
(what you typed) → **local estimate**. The middle one exists because a fresh
|
|
141
|
+
install has no capture yet:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cc-cockpit sync --block 23% --block-reset 1h55 --week 3% --week-reset 1h15
|
|
145
|
+
cc-cockpit sync # show anchors, samples and implied ceilings
|
|
146
|
+
cc-cockpit sync --reset
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Both the tray and the dashboard say which source is in use.
|
|
150
|
+
|
|
151
|
+
## How it works
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
~/.claude/projects/**/*.jsonl transcripts (usage per request)
|
|
155
|
+
~/.claude/sessions/*.json one entry per live CLI ─┐
|
|
156
|
+
statusline payload (stdin) official rate limits + context ├─> cockpit/
|
|
157
|
+
~/.local/share/cc-cockpit/events.ndjson <───────────────┘
|
|
158
|
+
~/.local/share/cc-cockpit/panel.json official snapshot
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- `collector.py` reads each transcript **from the last offset**, so a refresh
|
|
162
|
+
costs ~30 ms even with 190 MB of history.
|
|
163
|
+
- Events land in a dedicated NDJSON file. That matters: Claude Code **prunes
|
|
164
|
+
transcripts after ~30 days**, and from the first collection onward cc-cockpit
|
|
165
|
+
keeps the full history.
|
|
166
|
+
- Deduplication by `message.id:requestId`, so resuming a session is not counted
|
|
167
|
+
twice.
|
|
168
|
+
- `sessions.py` validates each pid against `/proc` **and** compares the
|
|
169
|
+
`starttime`, so a recycled pid is never mistaken for a live session.
|
|
170
|
+
- Prices live in `pricing.py`: cache writes at 1.25× (5m) and 2× (1h) of input,
|
|
171
|
+
cache reads at 0.1× (0.025× on Fable 5.1). The transcript separates the two
|
|
172
|
+
cache-write TTLs and the calculation uses that split instead of assuming 5m.
|
|
173
|
+
- `i18n.py` holds one catalogue for all three surfaces, plus locale-aware number
|
|
174
|
+
and currency formatting.
|
|
175
|
+
- `panel.py` keeps the official snapshot and appends a line to
|
|
176
|
+
`panel-history.ndjson` whenever the percentage changes.
|
|
177
|
+
|
|
178
|
+
## Honest limitations
|
|
179
|
+
|
|
180
|
+
- Without the statusline capture and without `limits`, the percentage is
|
|
181
|
+
relative to your own history, not to the real plan limit.
|
|
182
|
+
- The statusline only refreshes while a CLI session is rendering. That is
|
|
183
|
+
enough — what is not running cannot be consuming — but right after a long
|
|
184
|
+
gap the percentage may lag until the next render.
|
|
185
|
+
- Consumption from the Claude app shows up in the official percentage, never in
|
|
186
|
+
the local currency figures, which read Claude Code transcripts only.
|
|
187
|
+
- Models released after this version fall back to their family price (`opus`,
|
|
188
|
+
`sonnet`, `haiku`, `fable`) until they are added to `pricing.py`.
|
|
189
|
+
- `<synthetic>` rows are responses the CLI generates locally: they show up in
|
|
190
|
+
the request count and cost nothing.
|
|
191
|
+
|
|
192
|
+
## Packaging
|
|
193
|
+
|
|
194
|
+
`packaging/` holds the `.deb` build script and the Arch `PKGBUILD`; see
|
|
195
|
+
[packaging/README.md](packaging/README.md) for the release flow. A `v*` tag
|
|
196
|
+
builds the wheel, the sdist and the `.deb`, publishes to PyPI and attaches
|
|
197
|
+
everything to the GitHub release.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT — see [LICENSE](LICENSE).
|
|
202
|
+
|
|
203
|
+
Not affiliated with Anthropic.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# cc-cockpit
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
|
|
5
|
+
A Claude Code usage panel for GNOME: a tray indicator with a consumption ring,
|
|
6
|
+
a local dashboard and a terminal summary.
|
|
7
|
+
|
|
8
|
+
Everything is read from what Claude Code already writes under `~/.claude`. It
|
|
9
|
+
makes no network calls, reads no credentials and sends nothing anywhere.
|
|
10
|
+
|
|
11
|
+
The interface follows your OS language — English, Portuguese and Spanish are
|
|
12
|
+
bundled — and can be pinned in the config file or with `--lang`.
|
|
13
|
+
|
|
14
|
+
## What it shows
|
|
15
|
+
|
|
16
|
+
| | |
|
|
17
|
+
|---|---|
|
|
18
|
+
| **5h block** | how much the current rate-limit window has consumed, time to reset, hourly pace, projection to the end of the block, and how long until the reference ceiling. The window starts at the exact timestamp of its first request — not rounded to the hour — which is what makes the reset match what the CLI reports |
|
|
19
|
+
| **7 days / today / month** | rolling totals, as a percentage of your own historical peak |
|
|
20
|
+
| **Open sessions** | every live CLI instance: name, project, `busy`/`idle`, uptime, RAM, pid, and what that session has consumed |
|
|
21
|
+
| **Projects** | ranked by consumption across the whole history |
|
|
22
|
+
| **Blocks, days and hours** | time series showing when you actually spend |
|
|
23
|
+
| **Token mix** | input / output / cache write 5m / cache write 1h / cache read, with the cache hit rate |
|
|
24
|
+
| **Models, effort and subagents** | where the consumption really goes |
|
|
25
|
+
|
|
26
|
+
Usage is measured in **API-equivalent USD**: what those messages would cost on
|
|
27
|
+
the pay-as-you-go API. On a Pro/Max plan none of it is billed — the number works
|
|
28
|
+
as a weight unit for consumption and shows how much the plan returns.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
**Debian / Ubuntu** — the `.deb` pulls in the GTK dependencies by itself:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# from the latest release
|
|
36
|
+
sudo apt install ./cc-cockpit_0.2.0_all.deb
|
|
37
|
+
cc-cockpit setup
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Arch** — from the AUR:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
yay -S cc-cockpit # or: makepkg -si from packaging/PKGBUILD
|
|
44
|
+
cc-cockpit setup
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Any distribution** — pipx, reusing the system GTK bindings:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
sudo apt install python3-gi python3-cairo gir1.2-ayatanaappindicator3-0.1 # tray only
|
|
51
|
+
pipx install cc-cockpit --system-site-packages
|
|
52
|
+
cc-cockpit setup
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`--system-site-packages` is what lets the virtualenv see PyGObject and pycairo.
|
|
56
|
+
Without them the tray is unavailable, and the dashboard and `report` still work.
|
|
57
|
+
|
|
58
|
+
**From a checkout**:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/wallacemartinss/cc-cockpit
|
|
62
|
+
cd cc-cockpit && ./install.sh
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`cc-cockpit setup` registers the GNOME autostart entry, captures the statusline
|
|
66
|
+
(see below), checks the tray dependencies and runs the first collection.
|
|
67
|
+
`cc-cockpit setup --remove` undoes the autostart entry.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cc-cockpit # tray + dashboard in the background
|
|
71
|
+
cc-cockpit report # terminal summary
|
|
72
|
+
cc-cockpit serve --open # dashboard only (http://127.0.0.1:8765)
|
|
73
|
+
cc-cockpit json # everything as JSON, for scripting
|
|
74
|
+
cc-cockpit collect # ingest new transcripts and exit
|
|
75
|
+
cc-cockpit config # config path and contents
|
|
76
|
+
cc-cockpit --lang es report
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## The real numbers, from the statusline
|
|
80
|
+
|
|
81
|
+
Two things cannot be derived from local transcripts:
|
|
82
|
+
|
|
83
|
+
1. **The limit belongs to the account, not to the CLI.** Whatever you consume in
|
|
84
|
+
the Claude app counts against the same window and leaves nothing on disk, so
|
|
85
|
+
a window can start before your first local request.
|
|
86
|
+
2. **The weekly limit is a fixed window** with its own reset time, not the
|
|
87
|
+
rolling 7 days a local reader would assume.
|
|
88
|
+
|
|
89
|
+
Claude Code pipes a JSON payload into the statusline command on every render,
|
|
90
|
+
and it carries exactly what the plan panel shows:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
"rate_limits": {
|
|
94
|
+
"five_hour": {"used_percentage": 23, "resets_at": 1788800000},
|
|
95
|
+
"seven_day": {"used_percentage": 3, "resets_at": 1788790000}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Register the capture once — no credentials, no undocumented endpoint:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
cc-cockpit statusline --install
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
It writes `statusLine` into `~/.claude/settings.json`, keeping a `.bak`. If you
|
|
106
|
+
already had one, it is chained rather than replaced, so its output still shows
|
|
107
|
+
in the CLI. The captured payload also carries the **context window percentage
|
|
108
|
+
per session**, which the dashboard shows next to each open session.
|
|
109
|
+
|
|
110
|
+
From then on the official percentage is the source of truth, and it reveals the
|
|
111
|
+
real ceiling — `local consumption ÷ official percentage` — so the currency
|
|
112
|
+
figures stay meaningful too.
|
|
113
|
+
|
|
114
|
+
### When there is no statusline data yet
|
|
115
|
+
|
|
116
|
+
Numbers fall back, in order of trust: **official** (statusline) → **anchored**
|
|
117
|
+
(what you typed) → **local estimate**. The middle one exists because a fresh
|
|
118
|
+
install has no capture yet:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cc-cockpit sync --block 23% --block-reset 1h55 --week 3% --week-reset 1h15
|
|
122
|
+
cc-cockpit sync # show anchors, samples and implied ceilings
|
|
123
|
+
cc-cockpit sync --reset
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Both the tray and the dashboard say which source is in use.
|
|
127
|
+
|
|
128
|
+
## How it works
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
~/.claude/projects/**/*.jsonl transcripts (usage per request)
|
|
132
|
+
~/.claude/sessions/*.json one entry per live CLI ─┐
|
|
133
|
+
statusline payload (stdin) official rate limits + context ├─> cockpit/
|
|
134
|
+
~/.local/share/cc-cockpit/events.ndjson <───────────────┘
|
|
135
|
+
~/.local/share/cc-cockpit/panel.json official snapshot
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- `collector.py` reads each transcript **from the last offset**, so a refresh
|
|
139
|
+
costs ~30 ms even with 190 MB of history.
|
|
140
|
+
- Events land in a dedicated NDJSON file. That matters: Claude Code **prunes
|
|
141
|
+
transcripts after ~30 days**, and from the first collection onward cc-cockpit
|
|
142
|
+
keeps the full history.
|
|
143
|
+
- Deduplication by `message.id:requestId`, so resuming a session is not counted
|
|
144
|
+
twice.
|
|
145
|
+
- `sessions.py` validates each pid against `/proc` **and** compares the
|
|
146
|
+
`starttime`, so a recycled pid is never mistaken for a live session.
|
|
147
|
+
- Prices live in `pricing.py`: cache writes at 1.25× (5m) and 2× (1h) of input,
|
|
148
|
+
cache reads at 0.1× (0.025× on Fable 5.1). The transcript separates the two
|
|
149
|
+
cache-write TTLs and the calculation uses that split instead of assuming 5m.
|
|
150
|
+
- `i18n.py` holds one catalogue for all three surfaces, plus locale-aware number
|
|
151
|
+
and currency formatting.
|
|
152
|
+
- `panel.py` keeps the official snapshot and appends a line to
|
|
153
|
+
`panel-history.ndjson` whenever the percentage changes.
|
|
154
|
+
|
|
155
|
+
## Honest limitations
|
|
156
|
+
|
|
157
|
+
- Without the statusline capture and without `limits`, the percentage is
|
|
158
|
+
relative to your own history, not to the real plan limit.
|
|
159
|
+
- The statusline only refreshes while a CLI session is rendering. That is
|
|
160
|
+
enough — what is not running cannot be consuming — but right after a long
|
|
161
|
+
gap the percentage may lag until the next render.
|
|
162
|
+
- Consumption from the Claude app shows up in the official percentage, never in
|
|
163
|
+
the local currency figures, which read Claude Code transcripts only.
|
|
164
|
+
- Models released after this version fall back to their family price (`opus`,
|
|
165
|
+
`sonnet`, `haiku`, `fable`) until they are added to `pricing.py`.
|
|
166
|
+
- `<synthetic>` rows are responses the CLI generates locally: they show up in
|
|
167
|
+
the request count and cost nothing.
|
|
168
|
+
|
|
169
|
+
## Packaging
|
|
170
|
+
|
|
171
|
+
`packaging/` holds the `.deb` build script and the Arch `PKGBUILD`; see
|
|
172
|
+
[packaging/README.md](packaging/README.md) for the release flow. A `v*` tag
|
|
173
|
+
builds the wheel, the sdist and the `.deb`, publishes to PyPI and attaches
|
|
174
|
+
everything to the GitHub release.
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT — see [LICENSE](LICENSE).
|
|
179
|
+
|
|
180
|
+
Not affiliated with Anthropic.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cc-cockpit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Claude Code usage panel for GNOME: tray indicator, local dashboard and terminal summary
|
|
5
|
+
Author: Wallace Martins da Silva
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/wallacemartinss/cc-cockpit
|
|
8
|
+
Project-URL: Issues, https://github.com/wallacemartinss/cc-cockpit/issues
|
|
9
|
+
Keywords: claude,claude-code,usage,gnome,tray,appindicator
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: X11 Applications :: GTK
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: tray
|
|
20
|
+
Requires-Dist: PyGObject>=3.42; extra == "tray"
|
|
21
|
+
Requires-Dist: pycairo>=1.20; extra == "tray"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# cc-cockpit
|
|
25
|
+
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
|
|
28
|
+
A Claude Code usage panel for GNOME: a tray indicator with a consumption ring,
|
|
29
|
+
a local dashboard and a terminal summary.
|
|
30
|
+
|
|
31
|
+
Everything is read from what Claude Code already writes under `~/.claude`. It
|
|
32
|
+
makes no network calls, reads no credentials and sends nothing anywhere.
|
|
33
|
+
|
|
34
|
+
The interface follows your OS language — English, Portuguese and Spanish are
|
|
35
|
+
bundled — and can be pinned in the config file or with `--lang`.
|
|
36
|
+
|
|
37
|
+
## What it shows
|
|
38
|
+
|
|
39
|
+
| | |
|
|
40
|
+
|---|---|
|
|
41
|
+
| **5h block** | how much the current rate-limit window has consumed, time to reset, hourly pace, projection to the end of the block, and how long until the reference ceiling. The window starts at the exact timestamp of its first request — not rounded to the hour — which is what makes the reset match what the CLI reports |
|
|
42
|
+
| **7 days / today / month** | rolling totals, as a percentage of your own historical peak |
|
|
43
|
+
| **Open sessions** | every live CLI instance: name, project, `busy`/`idle`, uptime, RAM, pid, and what that session has consumed |
|
|
44
|
+
| **Projects** | ranked by consumption across the whole history |
|
|
45
|
+
| **Blocks, days and hours** | time series showing when you actually spend |
|
|
46
|
+
| **Token mix** | input / output / cache write 5m / cache write 1h / cache read, with the cache hit rate |
|
|
47
|
+
| **Models, effort and subagents** | where the consumption really goes |
|
|
48
|
+
|
|
49
|
+
Usage is measured in **API-equivalent USD**: what those messages would cost on
|
|
50
|
+
the pay-as-you-go API. On a Pro/Max plan none of it is billed — the number works
|
|
51
|
+
as a weight unit for consumption and shows how much the plan returns.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
**Debian / Ubuntu** — the `.deb` pulls in the GTK dependencies by itself:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# from the latest release
|
|
59
|
+
sudo apt install ./cc-cockpit_0.2.0_all.deb
|
|
60
|
+
cc-cockpit setup
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Arch** — from the AUR:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
yay -S cc-cockpit # or: makepkg -si from packaging/PKGBUILD
|
|
67
|
+
cc-cockpit setup
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Any distribution** — pipx, reusing the system GTK bindings:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
sudo apt install python3-gi python3-cairo gir1.2-ayatanaappindicator3-0.1 # tray only
|
|
74
|
+
pipx install cc-cockpit --system-site-packages
|
|
75
|
+
cc-cockpit setup
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`--system-site-packages` is what lets the virtualenv see PyGObject and pycairo.
|
|
79
|
+
Without them the tray is unavailable, and the dashboard and `report` still work.
|
|
80
|
+
|
|
81
|
+
**From a checkout**:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/wallacemartinss/cc-cockpit
|
|
85
|
+
cd cc-cockpit && ./install.sh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`cc-cockpit setup` registers the GNOME autostart entry, captures the statusline
|
|
89
|
+
(see below), checks the tray dependencies and runs the first collection.
|
|
90
|
+
`cc-cockpit setup --remove` undoes the autostart entry.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cc-cockpit # tray + dashboard in the background
|
|
94
|
+
cc-cockpit report # terminal summary
|
|
95
|
+
cc-cockpit serve --open # dashboard only (http://127.0.0.1:8765)
|
|
96
|
+
cc-cockpit json # everything as JSON, for scripting
|
|
97
|
+
cc-cockpit collect # ingest new transcripts and exit
|
|
98
|
+
cc-cockpit config # config path and contents
|
|
99
|
+
cc-cockpit --lang es report
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## The real numbers, from the statusline
|
|
103
|
+
|
|
104
|
+
Two things cannot be derived from local transcripts:
|
|
105
|
+
|
|
106
|
+
1. **The limit belongs to the account, not to the CLI.** Whatever you consume in
|
|
107
|
+
the Claude app counts against the same window and leaves nothing on disk, so
|
|
108
|
+
a window can start before your first local request.
|
|
109
|
+
2. **The weekly limit is a fixed window** with its own reset time, not the
|
|
110
|
+
rolling 7 days a local reader would assume.
|
|
111
|
+
|
|
112
|
+
Claude Code pipes a JSON payload into the statusline command on every render,
|
|
113
|
+
and it carries exactly what the plan panel shows:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"rate_limits": {
|
|
117
|
+
"five_hour": {"used_percentage": 23, "resets_at": 1788800000},
|
|
118
|
+
"seven_day": {"used_percentage": 3, "resets_at": 1788790000}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Register the capture once — no credentials, no undocumented endpoint:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cc-cockpit statusline --install
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
It writes `statusLine` into `~/.claude/settings.json`, keeping a `.bak`. If you
|
|
129
|
+
already had one, it is chained rather than replaced, so its output still shows
|
|
130
|
+
in the CLI. The captured payload also carries the **context window percentage
|
|
131
|
+
per session**, which the dashboard shows next to each open session.
|
|
132
|
+
|
|
133
|
+
From then on the official percentage is the source of truth, and it reveals the
|
|
134
|
+
real ceiling — `local consumption ÷ official percentage` — so the currency
|
|
135
|
+
figures stay meaningful too.
|
|
136
|
+
|
|
137
|
+
### When there is no statusline data yet
|
|
138
|
+
|
|
139
|
+
Numbers fall back, in order of trust: **official** (statusline) → **anchored**
|
|
140
|
+
(what you typed) → **local estimate**. The middle one exists because a fresh
|
|
141
|
+
install has no capture yet:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cc-cockpit sync --block 23% --block-reset 1h55 --week 3% --week-reset 1h15
|
|
145
|
+
cc-cockpit sync # show anchors, samples and implied ceilings
|
|
146
|
+
cc-cockpit sync --reset
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Both the tray and the dashboard say which source is in use.
|
|
150
|
+
|
|
151
|
+
## How it works
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
~/.claude/projects/**/*.jsonl transcripts (usage per request)
|
|
155
|
+
~/.claude/sessions/*.json one entry per live CLI ─┐
|
|
156
|
+
statusline payload (stdin) official rate limits + context ├─> cockpit/
|
|
157
|
+
~/.local/share/cc-cockpit/events.ndjson <───────────────┘
|
|
158
|
+
~/.local/share/cc-cockpit/panel.json official snapshot
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- `collector.py` reads each transcript **from the last offset**, so a refresh
|
|
162
|
+
costs ~30 ms even with 190 MB of history.
|
|
163
|
+
- Events land in a dedicated NDJSON file. That matters: Claude Code **prunes
|
|
164
|
+
transcripts after ~30 days**, and from the first collection onward cc-cockpit
|
|
165
|
+
keeps the full history.
|
|
166
|
+
- Deduplication by `message.id:requestId`, so resuming a session is not counted
|
|
167
|
+
twice.
|
|
168
|
+
- `sessions.py` validates each pid against `/proc` **and** compares the
|
|
169
|
+
`starttime`, so a recycled pid is never mistaken for a live session.
|
|
170
|
+
- Prices live in `pricing.py`: cache writes at 1.25× (5m) and 2× (1h) of input,
|
|
171
|
+
cache reads at 0.1× (0.025× on Fable 5.1). The transcript separates the two
|
|
172
|
+
cache-write TTLs and the calculation uses that split instead of assuming 5m.
|
|
173
|
+
- `i18n.py` holds one catalogue for all three surfaces, plus locale-aware number
|
|
174
|
+
and currency formatting.
|
|
175
|
+
- `panel.py` keeps the official snapshot and appends a line to
|
|
176
|
+
`panel-history.ndjson` whenever the percentage changes.
|
|
177
|
+
|
|
178
|
+
## Honest limitations
|
|
179
|
+
|
|
180
|
+
- Without the statusline capture and without `limits`, the percentage is
|
|
181
|
+
relative to your own history, not to the real plan limit.
|
|
182
|
+
- The statusline only refreshes while a CLI session is rendering. That is
|
|
183
|
+
enough — what is not running cannot be consuming — but right after a long
|
|
184
|
+
gap the percentage may lag until the next render.
|
|
185
|
+
- Consumption from the Claude app shows up in the official percentage, never in
|
|
186
|
+
the local currency figures, which read Claude Code transcripts only.
|
|
187
|
+
- Models released after this version fall back to their family price (`opus`,
|
|
188
|
+
`sonnet`, `haiku`, `fable`) until they are added to `pricing.py`.
|
|
189
|
+
- `<synthetic>` rows are responses the CLI generates locally: they show up in
|
|
190
|
+
the request count and cost nothing.
|
|
191
|
+
|
|
192
|
+
## Packaging
|
|
193
|
+
|
|
194
|
+
`packaging/` holds the `.deb` build script and the Arch `PKGBUILD`; see
|
|
195
|
+
[packaging/README.md](packaging/README.md) for the release flow. A `v*` tag
|
|
196
|
+
builds the wheel, the sdist and the `.deb`, publishes to PyPI and attaches
|
|
197
|
+
everything to the GitHub release.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT — see [LICENSE](LICENSE).
|
|
202
|
+
|
|
203
|
+
Not affiliated with Anthropic.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
cc_cockpit.egg-info/PKG-INFO
|
|
5
|
+
cc_cockpit.egg-info/SOURCES.txt
|
|
6
|
+
cc_cockpit.egg-info/dependency_links.txt
|
|
7
|
+
cc_cockpit.egg-info/entry_points.txt
|
|
8
|
+
cc_cockpit.egg-info/requires.txt
|
|
9
|
+
cc_cockpit.egg-info/top_level.txt
|
|
10
|
+
cockpit/__init__.py
|
|
11
|
+
cockpit/__main__.py
|
|
12
|
+
cockpit/anchors.py
|
|
13
|
+
cockpit/calibration.py
|
|
14
|
+
cockpit/cli.py
|
|
15
|
+
cockpit/collector.py
|
|
16
|
+
cockpit/config.py
|
|
17
|
+
cockpit/desktop.py
|
|
18
|
+
cockpit/i18n.py
|
|
19
|
+
cockpit/icon.py
|
|
20
|
+
cockpit/panel.py
|
|
21
|
+
cockpit/pricing.py
|
|
22
|
+
cockpit/server.py
|
|
23
|
+
cockpit/sessions.py
|
|
24
|
+
cockpit/stats.py
|
|
25
|
+
cockpit/statusline.py
|
|
26
|
+
cockpit/tray.py
|
|
27
|
+
cockpit/web/index.html
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cockpit
|