- JavaScript 80.4%
- Shell 10.5%
- Makefile 8.3%
- CSS 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The extension targeted shell-version 50 but was written against the legacy
GNOME 3.x API. Shell 45+ loads extensions as ES modules, so `imports.ui.main`
pulled in a module through the classic script loader and the shell refused to
load it:
SyntaxError: import declarations may only appear at top level of a module
@ resource:///org/gnome/shell/ui/main.js:1:1
The error points at the shell's own main.js rather than at this extension,
which makes it read like a shell bug.
Ported both entry points to ESM: extension.js now exports a default class
extending Extension with the indicator as a registered PanelMenu.Button
subclass, and prefs.js implements fillPreferencesWindow with Adw rows bound
via settings.bind.
Four further bugs would each have broken it after the port:
- GLib.UTF8_TO_STRING_TRIMMED does not exist; use TextDecoder.
- Gio.File.new_for_uri on an http URI needs the gvfs http backend, which is
not always installed. Use Soup.Session instead.
- A second PopupMenu was constructed and its actor parented to the button.
PanelMenu.Button already provides this.menu.
- PopupMenuItem.label is a St.Label, not a string. Assigning a string to it
breaks the widget; set item.label.text.
Also locate the GPU by reading each hwmonN/name rather than hardcoding
hwmon6, since those indices are not stable across boots; treat hal0's
tokens_completed as the rolling one hour window it is, rather than
differencing it as a cumulative counter; read update-interval with get_int to
match its schema type; and tear down the timeout, Soup session and cancellable
on disable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
| schemas | ||
| .gitignore | ||
| extension.js | ||
| LICENSE | ||
| Makefile | ||
| metadata.json | ||
| prefs.js | ||
| README.md | ||
| stylesheet.css | ||
| test-nested.sh | ||
Power & Token Tracker
A GNOME Shell extension that shows live GPU power draw in the panel and works out what your AI tokens actually cost to generate.
The panel button shows current GPU watts. Opening it shows current and average power, tokens generated in the last hour, your energy cost per hour, and the resulting cost per million tokens.
Requirements
- GNOME Shell 45 or later (developed against 50)
- A GPU exposing power via hwmon (
amdgpu,nvidia,i915orxe) - A hal0 instance for token metrics
Install
make install
Then log out and back in — on Wayland the shell cannot load a new extension without restarting the session — and enable it:
gnome-extensions enable power-token-tracker@jhgaylor.local
For development, make link symlinks this checkout into place instead of copying,
so edits only need a session restart rather than a reinstall.
Configuration
gnome-extensions prefs power-token-tracker@jhgaylor.local
| Setting | Default | Meaning |
|---|---|---|
| Cost per kWh | 0.12 |
Your electricity rate, in dollars |
| Update interval | 10 |
Seconds between refreshes |
| Show cost per token | on |
Whether to compute cost per million tokens |
| hal0 API URL | http://localhost:8080 |
Base URL; /api/stats is appended |
How it works
Power is read from /sys/class/hwmon/hwmonN/power1_average (falling back to
power1_input), in microwatts. The hwmonN index is not stable across boots, so
the extension locates the GPU by reading each hwmonN/name rather than hardcoding
an index. A rolling 360-sample window backs the average.
Tokens come from hal0's /api/stats, via totals.tokens_completed. That field
is a rolling one hour window, not a cumulative counter. Since it is already
per-hour, and energy cost is already per-hour, cost per million tokens is:
costPerHour = (avgWatts / 1000) * costPerKwh
costPerMillionTokens = costPerHour / tokensPerHour * 1_000_000
This is a measure of marginal generation cost — electricity to run the GPU. It does not include hardware, idle draw outside the sample window, or anything upstream.
Testing
The running shell caches extension modules and cannot re-import them, so a syntax
error normally costs you a log out / log in to discover. make check loads the
extension in a throwaway headless shell on a private D-Bus session and reports
whether it reached ACTIVE with no errors, without touching your live session.
License
MIT