swinksandClaude Opus 4.8 d4571ad39e AppImage-Autostart unter Wayland reparieren
Der Wechsel auf X11 (noetig, weil Wayland weder Selbstpositionierung noch
Always-on-Top erlaubt) startete die App unter Wayland gar nicht neu: Electrons
app.relaunch() legt den Nachfolger ueber einen Hilfsprozess an, der im
/tmp-Mount des AppImage liegt. Beim Beenden der alten Instanz wird der Mount
abgehaengt und reisst den Hilfsprozess mit, bevor er den Nachfolger starten
kann -- die App war nach dem Doppelklick einfach weg.

Fuer das AppImage den Nachfolger jetzt selbst als abgekoppelten Prozess
(child_process.spawn mit detached/unref) auf das echte Abbild starten; das
ueberlebt das Abhaengen des Mounts. Quelle und .deb behalten app.relaunch(),
da dort der Hilfsprozess auf einem bleibenden Pfad liegt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-05 22:21:13 +02:00
2026-07-22 21:52:08 +02:00
2026-07-22 21:52:08 +02:00
2026-07-22 21:52:08 +02:00

Claude Live Dashboard

Ein rahmenloses Always-on-Top-Widget für Windows und Linux, das die Auslastung des Claude-Plans live anzeigt: 5-Stunden-Fenster, Wochenverbrauch, Reset-Countdown, Tokenverbrauch je Modell und die Hochrechnung auf das Fensterende.

Die Daten stammen aus den Transkripten, die Claude Code ohnehin unter ~/.claude/projects/**/*.jsonl schreibt. Es wird nichts installiert, nichts mitgeschnitten und standardmäßig keine Netzwerkverbindung aufgebaut.

Start

Node.js (ab Version 20) wird benötigt.

Windows

Ist Node nicht im PATH (etwa bei nvm-windows ohne aktive Version), genügt der Versionspfad:

$env:PATH = "$env:APPDATA\nvm\v22.22.1;$env:PATH"
npm install
npm start

Alternativ start.cmd doppelklicken.

Das Tray-Symbol landet unter Windows zunächst im Überlaufbereich hinter dem ^ in der Taskleiste; per Drag lässt es sich dauerhaft sichtbar machen.

Linux (Ubuntu)

sudo apt install nodejs npm   # falls noch nicht vorhanden
./start.sh

start.sh installiert fehlende Abhängigkeiten selbst und startet Electron; npm install && npm start tut dasselbe.

Das Tray-Symbol braucht unter GNOME die Erweiterung AppIndicator — beim Ubuntu-Desktop ist sie vorinstalliert und aktiv. Auf einer Minimalinstallation oder unter anderen Oberflächen:

sudo apt install gnome-shell-extension-appindicator

Ohne sie läuft das Widget weiter, nur das Symbol in der oberen Leiste fehlt. Anders als unter Windows ist im StatusNotifierItem-Standard nicht festgelegt, welcher Klick als Aktivierung zählt — verlässlich ist deshalb das Kontextmenü (Rechtsklick) mit „Dashboard anzeigen“ als erstem Eintrag.

Wayland: Ab Electron 36 wählt Chromium in einer Wayland-Sitzung von sich aus Wayland — dort darf sich ein Fenster aber weder selbst positionieren noch dauerhaft in den Vordergrund legen, und genau das ist der Kern dieses Widgets. Die App startet sich deshalb unter Wayland einmalig selbst mit --ozone-platform=x11 neu und läuft über XWayland. Das geschieht automatisch, es ist nichts einzustellen.

Der Schalter muss auf der Kommandozeile stehen: Ozone legt die Plattform fest, bevor das Main-Skript läuft — app.commandLine.appendSwitch() und ELECTRON_OZONE_PLATFORM_HINT kommen beide zu spät. Wer die Automatik umgehen will, setzt eine der beiden Größen von Hand; dann greift der Neustart nicht mehr:

ELECTRON_OZONE_PLATFORM_HINT=wayland ./start.sh   # nativ Wayland, ohne Positionierung

Bedienung

Aktion Wirkung
Kopfzeile ziehen Fenster verschieben (Position wird gemerkt)
Statuspunkt (links vom Zahnrad) Fehler-/Ereignis-Log öffnen
Einstellungen öffnen
„Details“ Modell-Aufschlüsselung, Tempo und Datengrundlage aufklappen
Ausblenden — Rückkehr über das Tray-Symbol
Tray-Klick Ein-/Ausblenden
Tray-Menü Deckkraft, Klick-Durchlässigkeit, Autostart, Einstellungen, Beenden

Einstellungen

Das Zahnrad in der Kopfzeile öffnet einen Dialog für alle Felder der config.json: Deckkraft, Klick-Durchlässigkeit, Autostart, Serverabfrage, Bezugsgrößen, Gewichtung und Wochenfenster.

Gespeicherte Änderungen greifen sofort — ohne Neustart. Der Dialog liest und schreibt dieselbe Datei, die sich auch von Hand bearbeiten lässt: Kommentarfelder (_hinweis und Verwandte) und unbekannte Einträge bleiben dabei unangetastet, weil die vorhandene Datei nur ergänzt und nicht ersetzt wird. Strg+S speichert, Esc schließt.

Autostart ist kein Feld der Datei, sondern ein Systemzustand — er wird deshalb sofort beim Umschalten übernommen, unabhängig vom Speichern.

„Klicks durchlassen“ macht das Widget für Mausereignisse transparent — es liegt dann über der Arbeit, ohne sie zu behindern. Zurückschalten geht über das Tray-Menü.

Endpunkt-Status & Ereignis-Log

Der Punkt links vom Zahnrad zeigt den Zustand der beiden Datenquellen — Symbol und Farbe, nie Farbe allein:

Zustand Bedeutung
● grün Beide Quellen funktionieren
◆ gelb Serverabfrage gestört (App rechnet lokal weiter)
◆ rot Lokale Transkripte nicht lesbar — die Kerndatenquelle fehlt

Ein Klick öffnet ein eigenes Fenster mit dem chronologischen, zeitgestempelten Protokoll aller Störungen (Lesefehler, Dateiüberwachung, Serverabfrage) sowie App-Ereignissen wie Erstinstallation und Updates. Das Protokoll übersteht Neustarts und das Speichern der Einstellungen — es liegt in state.json — und lässt sich über „Log löschen“ im selben Fenster zurücksetzen.

Was angezeigt wird

Laufende Sitzung — Auslastung des aktuellen 5-Stunden-Fensters, dazu verbrauchte Tokens und Tempo.

Wochenkontingent — das übergeordnete Limit über alle Modelle, mit exaktem Reset-Zeitpunkt.

Nutzungsguthaben — der Budget-Zustand jenseits des Plan-Kontingents (verbraucht von Monatslimit). Erscheint nur, wenn der Server ihn meldet.

Darunter die eigentliche Kernaussage: wie lange das Kontingent bei diesem Tempo noch reicht — gerechnet in aktiver Arbeitszeit, nicht in Kalenderzeit. Eine Hochrechnung der Burn-Rate auf fünf Kalendertage wäre Unsinn, weil niemand durchgehend arbeitet.

Woher die Werte kommen

Standardmäßig fragt das Dashboard denselben Endpunkt ab, den auch /usage nutzt (GET /api/oauth/usage bei api.anthropic.com). Damit sind die Prozentwerte, Schweregrade und Reset-Zeitpunkte exakt — sekundengenau und ohne Schätzung.

Das Zugriffstoken wird aus ~/.claude/.credentials.json gelesen, nie gespeichert, nie protokolliert und nur an diesen Host gesendet. Es gibt bewusst keinen eigenen Refresh-Flow: Läuft das Token ab, pausiert die Abfrage, bis Claude Code es erneuert hat. Nach drei Fehlversuchen schaltet sie sich für die Sitzung ab.

Abschalten über config.json:

{ "oauth": { "enabled": false } }

Wichtig: Der Endpunkt ist nicht dokumentiert und kann durch ein Update brechen. Deshalb rechnet das Dashboard immer auch lokal weiter — fällt die Abfrage aus, läuft es ohne Unterbrechung auf den eigenen Zahlen weiter, nur eben mit Näherungswerten. Die Anzeige sagt jederzeit, welcher Fall vorliegt:

Anzeige Bedeutung
exakt (Server) Wert vom Server, entspricht /usage — nur mit Stufe 2
eigener Wert limits aus config.json
kalibriert aus mindestens 5 eigenen abgeschlossenen Fenstern abgeleitet
geschätzt noch zu wenige Messungen, grober Anhaltspunkt

Solange die Serverabfrage läuft, kalibriert sich das Dashboard selbst: Der Server nennt den exakten Anteil, lokal ist der gewichtete Verbrauch im selben Fenster bekannt — daraus folgt die Bezugsgröße unmittelbar. Auch das Wochenfenster wird aus dem gemeldeten Reset-Zeitpunkt abgeleitet, nicht geraten.

Die folgenden Abschnitte betreffen nur den Fall, dass die Abfrage nicht verfügbar ist.

Kalibrieren (Rückfallebene)

Ohne Serverabfrage nimmt das Dashboard das höchste je beobachtete Fenstervolumen als untere Schranke des Limits. Das ist grob. Besser: den Prozentwert in Einstellungen ▸ Nutzung ablesen und unmittelbar danach:

npm run calibrate -- --week 14           # nur rechnen
npm run calibrate -- --week 14 --write   # in config.json übernehmen
npm run calibrate -- --block 37 --write  # 5-Stunden-Fenster

Das Werkzeug teilt den aktuellen Verbrauch durch den angezeigten Anteil und erhält so die Bezugsgröße exakt. Danach das Dashboard neu starten.

Steht in der Nutzungsanzeige ein fester Reset-Zeitpunkt („Zurücksetzung Mo., 21:59“), gehört er in config.json — sonst passt das Fenster nicht zum kalibrierten Wert:

{ "weekResetWeekday": 1, "weekResetHour": 21, "weekResetMinute": 59 }

(0 = Sonntag, 1 = Montag …) Ohne diese Angabe rechnet das Dashboard mit einem rollierenden 7-Tage-Fenster und zeigt bewusst keinen Countdown, weil ein rollierendes Fenster keinen Reset-Zeitpunkt hat.

Gewichtung

Tokens zählen nicht gleich: Ausgabe wiegt stärker als ein Cache-Treffer, Opus stärker als Sonnet oder Haiku. Die Faktoren stehen in config.json.

Weichen zwei Kalibrierungen mit unterschiedlichem Modellmix deutlich voneinander ab, stimmen diese Gewichte nicht — dann dort nachziehen, statt das Limit hin- und herzuschieben. Ein einzelner Kalibrierpunkt legt nur den Maßstab fest, nicht die Gewichte.

Aufbau

src/main/index.js        Fenster, Tray, IPC, Autostart
src/main/collector.js    Watch-Schleife, Zustandsaufbau
src/main/jsonl.js        inkrementeller Reader, Parser, Dedup
src/main/blocks.js       5h-Blöcke, Wochenfenster, Burn-Rate
src/main/limits.js       Plan-Erkennung, Kalibrierung, Gewichtung
src/main/oauth-usage.js  Serverabfrage, gekapselt und ausfallsicher
src/main/calibrate.js    Kalibrierung gegen die echte Anzeige
src/main/store.js        state.json, config.json
src/main/paths.js        Speicherorte für Konfiguration und Zustand
src/main/autostart.js    Anmeldestart je Betriebssystem
src/preload.js           contextBridge fürs Widget
src/settings-preload.js  contextBridge für den Einstellungsdialog
src/errors-preload.js    contextBridge fürs Fehler-/Ereignis-Log
src/renderer/            Widget-Oberfläche
src/settings/            Einstellungsdialog
src/errors/              Fehler-/Ereignis-Log-Fenster

Alle Dateizugriffe und Rechnungen passieren im Main-Prozess; der Renderer bekommt fertige Zahlen und lässt nur den Countdown lokal weiterlaufen.

Zwei Details, die nicht offensichtlich sind:

  • Datei-Offsets werden nicht persistiert. Innerhalb einer Sitzung sorgen sie dafür, dass nur das Delta gelesen wird. Über einen Neustart hinweg wären sie schädlich, weil der Aggregator leer startet und die Historie sonst übersprungen würde. Ein Vollscan über 15 MB kostet rund 70 ms.
  • Dedup ist nicht optional. Claude Code schreibt dieselbe Nachricht bei Retries und beim Kompaktieren mehrfach ins Transkript; ohne Dedup über message.id wären alle Zahlen zu hoch.

Version & Updates

Die App erkennt beim Start selbst, ob es sich um eine Erstinstallation oder ein Update handelt: Sie vergleicht app.getVersion() (aus package.json, plattformunabhängig für Windows und Linux) mit der zuletzt in state.json gemerkten Version. Bei einer neuen Version erscheint einmalig eine native Systembenachrichtigung, und das Ereignis landet zeitgestempelt im Fehler-/Ereignis-Log (siehe oben). Bestehende Konfiguration und Kalibrierung bleiben davon unberührt — geschrieben wird ausschließlich das eine Feld state.json:appVersion.

Voraussetzung dafür ist eine bei jedem Release erhöhte Versionsnummer. Vor jedem Build deshalb zuerst version in package.json erhöhen (SemVer: 1.1.01.2.0 für neue Funktionen, 1.1.1 für Fehlerbehebungen). Ohne diesen Schritt erkennt die App den neuen Build nicht als Update, und der Installer überschreibt in release/ stillschweigend die Datei der vorherigen Version, weil deren Name (artifactName) die Versionsnummer enthält:

npm version minor    # oder: patch / major — schreibt package.json, kein Tag/Commit nötig
npm run dist

npm version legt standardmäßig auch einen Git-Commit und -Tag an; ohne das genügt es, version in package.json von Hand zu ändern.

Release bauen

Gebaut wird jeweils auf dem Zielsystem — electron-builder kann .deb nicht sinnvoll von Windows aus erzeugen und umgekehrt keine signierten .exe unter Linux. Beide Linux-Ziele (AppImage, .deb) brauchen zudem Linux-eigene Werkzeuge (mksquashfs bzw. fpm) und lassen sich nicht unter Windows erzeugen, auch nicht über WSL ohne eine dort eingerichtete Node.js- bzw. Ruby-Umgebung.

Windows

npm run dist    # Installer + portable Fassung nach release/
npm run pack    # nur entpackt nach release/win-unpacked (schneller Test)

Ergebnis in release/ (Version aus package.json, siehe oben):

Datei Zweck
Claude Live Dashboard-<version>-x64.exe NSIS-Installer, ~97 MB
Claude Live Dashboard-<version>-portable.exe läuft ohne Installation

Der Installer läuft ohne Administratorrechte (perMachine: false), installiert also ins Benutzerprofil. Zielverzeichnis ist wählbar, Desktop- und Startmenü-Verknüpfung werden angelegt. Bei der Deinstallation bleiben Konfiguration und Kalibrierung erhalten (deleteAppDataOnUninstall: false).

Nicht signiert. Ohne Code-Signing-Zertifikat zeigt Windows beim ersten Start einen SmartScreen-Hinweis („Der Computer wurde durch Windows geschützt“) — über Weitere Informationen ▸ Trotzdem ausführen zu bestätigen. Für eine Weitergabe an andere wäre ein Zertifikat nötig; für den Eigenbedarf ist es verzichtbar.

Linux

npm run dist:linux    # AppImage + .deb nach release/
npm run pack:linux    # nur entpackt nach release/linux-unpacked

Ergebnis in release/:

Datei Zweck
Claude Live Dashboard-<version>-x64.AppImage läuft ohne Installation
Claude Live Dashboard-<version>-amd64.deb Installation per sudo apt install ./…deb

Das AppImage muss einmal ausführbar gemacht werden (chmod +x) und braucht libfuse2. Es trägt sich nicht selbst ins Anwendungsmenü ein — der Autostart über das Tray-Menü funktioniert trotzdem, weil die App den Pfad des Abbilds aus APPIMAGE liest und nicht den temporären Einhängepunkt. Das .deb bringt Menüeintrag und Symbol mit und installiert nach /opt/Claude Live Dashboard.

Ubuntu 24.04 und AppImage. Seit 24.04 beschränkt AppArmor unprivilegierte User-Namespaces; die Chromium-Sandbox kann dann beim Start fehlschlagen (SUID sandbox helper binary … is not configured correctly). Zwei Auswege: das AppImage mit --no-sandbox starten, oder ein AppArmor-Profil unter /etc/apparmor.d/ hinterlegen. Beim .deb tritt das nicht auf — dessen postinst setzt das SUID-Bit auf chrome-sandbox.

Konfiguration und Zustand

Beides liegt im Benutzerprofil, nicht im Programmverzeichnis — dort wäre es nach der Installation im asar-Archiv und schreibgeschützt:

Windows:  %APPDATA%\Claude Live Dashboard\config.json
          %APPDATA%\Claude Live Dashboard\state.json

Linux:    ~/.config/Claude Live Dashboard/config.json
          ~/.config/Claude Live Dashboard/state.json

Der Autostart ist kein Feld dieser Dateien: unter Windows steckt er in der Registry, unter Linux in ~/.config/autostart/claude-live-dashboard.desktop.

Beim ersten Start wird config.json aus der mitgelieferten Vorlage angelegt. Erreichbar über das Tray-Menü (Konfiguration öffnen / Datenordner öffnen).

Die mitgelieferte Vorlage enthält unter limits einen auf diesem System kalibrierten Wert als Rückfallebene. Für eine Weitergabe an andere sollte er entfernt werden — bei aktiver Serverabfrage wird er ohnehin nicht benutzt.

Gegenprobe

npm run dump          # Modell-Summen und alle 5h-Blöcke auf der Konsole
npx ccusage blocks    # unabhängige Referenz für Blockgrenzen und Summen

npm run dump gibt außerdem die Dauer des zweiten Polls aus — ohne neue Daten muss er 0 Bytes lesen und im einstelligen Millisekundenbereich liegen.

S
Description
Always-on-Top Mini-Dashboard fuer Claude-Plan-Auslastung unter Windows
Readme
215 KiB
2026-08-05 20:48:49 +00:00
Languages
JavaScript 75.5%
CSS 14%
HTML 9.8%
Batchfile 0.4%
Shell 0.3%