κλεψύδρα · the water clock, the allotted time draining.
Your Claude usage on the desktop, read off your own machine.
A small card that sits on the desktop and says where you are in the rolling five-hour window, what the day has cost, and how fast the current session is spending. The Athenian water clock timed a speech by letting the water out; this one does the same for a rate limit, which is the only reason to have it in view rather than behind a command.
It reads Claude Code's own logs on disk and works the rest out itself. In default mode it opens no connection to anything. About six hundred lines of plain Python and Debian's own GTK4 bindings, with no third-party dependencies, so the whole of it can be read in one sitting.
| Drag | Moves the card. Where you leave it is where it comes back |
| Click | Opens the detail panel, and closes it again. Rows with nothing to report hide themselves, so the panel stays as short as the day was |
| Middle-click | Next theme. Shift+scroll steps through them in either direction |
| Ctrl+scroll | Zoom, in steps of 5% |
Every gesture writes its result back to ~/.config/klepsydra/config.ini, so
the card you arrange is the card that starts next time.
Placement is the one thing that depends on your session. Wayland forbids an application from positioning its own window, so the widget asks for the X11 backend first and falls back to Wayland if there is no X server. Under X11 or XWayland it puts itself back where you left it; on a pure Wayland session it still runs, and the desktop decides where the card lands.
| Reading | |
|---|---|
| 5h window | Where you are in the rolling five-hour limit, and how long until it resets. On its own the widget estimates this against your own median session; under --limits it is the official figure |
| week | Seven days of usage, with a separate note once the weekly Opus quota passes half |
| today | Tokens and computed cost since local midnight, split by model |
| burn rate | Tokens a minute over the last ten minutes, which is where a heavy agent run shows up as it happens rather than afterwards |
The detail panel adds only what changes a decision: an eta for the limit
itself, the month's total, how much of the day went to background jobs rather
than to you typing, the day's cost split by project and by git branch, and a
twelve-hour sparkline. Web searches and, under --limits, whatever
extra-usage credit is left, appear on the days they apply to. Every row that
has nothing to report hides itself, so a quiet day shows a short panel.
Default mode makes no network connection at all. It only reads Claude Code's
logs, ~/.claude/projects/**/*.jsonl, the newer ~/.config/claude/projects/
location of the same, and $CLAUDE_CONFIG_DIR/projects/ if you have moved
them. It writes nothing outside its own config file and install directory,
executes nothing, and reports nothing anywhere. Both claims are cheap to check:
grep -rn "urllib\|socket\|http\|requests" klepsydra/ # network lives only in limits.py
strace -f -e trace=network klepsydra # empty in default mode--limits opts into exactly one request, GET https://api.anthropic.com/api/oauth/usage, which is the endpoint Claude Code's
own /usage calls. It authenticates with the token Claude Code has already
stored in ~/.claude/.credentials.json, read and never written, and sent to
Anthropic and nowhere else. The hostname is pinned in limits.py. The token is
deliberately never refreshed or rotated: when it expires the card says so and
falls back to its own estimates until you next use Claude Code.
That endpoint is undocumented and unofficial. It is Claude Code's own, reached
with your own credentials for your own account, but nothing obliges Anthropic to
keep it, and reading it with something other than Claude Code may sit outside
their terms of use. That is why it is opt-in and off by default, and why the
card works without it. If that is a line you would rather not stand near, leave
--limits alone and lose nothing except the reconciliation with usage that did
not come through Claude Code.
The logs are the limit of what can be known locally. They hold Claude Code and
nothing else, so a conversation on claude.ai spends the same allowance without
appearing here, which is the whole of what --limits is for. Cost is computed
from tokens against the published per-MTok prices, kept as a table in
collector.py and worth updating there when they move. The five-hour block is
reconstructed the way ccusage does it, floored to the hour and started afresh
after a gap of five, which is what the observed resets look like. Streamed
lines that arrive twice are counted once, by message.id:requestId.
Twenty palettes. midnight is the default, beside nord, dracula,
gruvbox, catppuccin, tokyo-night, solarized-dark, rose-pine,
everforest and terminal, with paper and solarized-light for a light
desktop. theme = auto follows GNOME's own light and dark preference.
Eight more come from Keraunos, whose
map is drawn as an instrument readout rather than as an interface. Both of its
media are here: tube, phosphor emitted on black, and chart, ink laid on a
chart recorder's cool grey roll. phosphor-green (P1, the oscilloscope),
phosphor-amber (P3) and phosphor-ice tint the tube by multiplying its
neutrals against a ratio normalised on its own luminance, so the hue moves and
the weight does not. crimson, demon and oil are borrowed schemes
(WildLeoKnight,
Chicknhawk and
GrafxKid).
Those eight are ramps rather than traffic lights. With no red to escalate into,
a filling meter climbs the palette's own rungs toward the colour Keraunos keeps
for a strike; on chart it runs the other way and a full meter goes black.
klepsydra --list-themes # print them all
klepsydra --theme nord # use one, and keep itYour own is six hex values in themes.py: bg, fg, border, and the
cool, warm and hot the meters shift through on the way to a limit.
Debian 12 or 13, GNOME.
sudo apt install python3-gi gir1.2-gtk-4.0 # usually already there on GNOME
git clone https://github.com/corvardt/klepsydra && cd klepsydra
./install.sh # local only
./install.sh --limits # with the official percentages
klepsydraThe installer copies the package to ~/.local/share/klepsydra, adds a launcher
and a GNOME autostart entry, and needs root for nothing but the apt line.
--no-autostart if you would rather start it yourself.
git pull && ./install.sh --update # keeps the flags it was installed with
./install.sh --uninstall # leaves ~/.config/klepsydra
./install.sh --uninstall --purge # config as wellEach release also ships a .deb, built by tools/make_deb.py out of the
standard library alone, so producing one needs no dpkg-dev. It installs
system-wide and lets apt handle the rest:
sudo apt install ./klepsydra_*.deb
sudo apt purge klepsydraTake one or the other. They install to different prefixes and share an
autostart filename, so a machine with both starts the install.sh copy rather
than two widgets.
To keep it on every workspace under Wayland, focus it and press Alt+Space,
then Always on Visible Workspace; GNOME remembers that per application. Under
Xorg, wmctrl -r 'Klepsydra' -b add,sticky,below pins it below everything
else. Right-click and Quit closes it.
| Path | Role |
|---|---|
klepsydra/collector.py |
The logs: finding them, parsing them, dropping duplicates, pricing them, and rebuilding the five-hour blocks |
klepsydra/limits.py |
The opt-in official figures, one pinned endpoint and no token refresh |
klepsydra/widget.py |
The card itself: the readouts, the detail panel, the gestures, the zoom |
klepsydra/config.py |
~/.config/klepsydra/config.ini, the only thing the widget writes |
klepsydra/themes.py |
The palettes |
klepsydra/style.css |
The look. Theme tokens, and pixel values that scale with the zoom |
install.sh |
User-level install, update and uninstall |
tools/make_deb.py |
Builds the .deb, standard library only |
tests/ |
Stdlib test runners, no pytest |
python3 tests/test_collector.py # pricing, dedup, five-hour blocks
python3 tests/test_config.py # config round trip
python3 tools/make_deb.py dist/ # the packageCI runs both suites on Python 3.9 and 3.13, builds the .deb, and parses every
theme's CSS under GTK4. No third-party dependencies, please: auditable in one
sitting is the point of the thing.
MIT. Do what you like with the code. There is nothing else in here to license: no vendored code, no bundled fonts, and no dependency beyond Python, GTK4 and Debian's own GIR bindings.
Klepsydra is an unofficial tool. It is not affiliated with, endorsed by, or
supported by Anthropic. "Claude" and "Claude Code" are Anthropic's trademarks,
used here only to say what this reads. The per-MTok prices in collector.py are
published figures transcribed for arithmetic, they go stale, and nothing here is
authoritative about what you have actually been charged. Anthropic's own numbers
are the ones that count.

