Skip to content
DarkoKuzmanovicPublic

About

KDE Plasma 6 widget for AI account usage: Claude, Codex, Grok, Kimi, Cursor, OpenCode Go, and CommandCode.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Kuota

AI account usage in your KDE Plasma panel.

Kuota shows the usage windows, reset times, and account limits reported by Claude, Codex, Grok, Kimi, Cursor, OpenCode Go, and CommandCode. Keep a compact summary in your panel and open the detail view when you need the full picture. The same detail view works as a desktop widget.

No Pi installation, permanent collector service, or runtime npm dependencies. Kuota reads existing credentials locally; it does not estimate account quota from your prompts, token logs, or local activity.

Kuota app screenshot

Installation · Providers and credentials · Troubleshooting · Development · Review and next steps

What it does

  • Panel summary: provider icons, labels, usage values, and configurable caution/critical colors. “Icons only” hides the label, not the usage value.
  • Detail view: provider tabs, genuine usage windows, progress bars, reset countdowns, last-successful update time, and provider-specific facts.
  • Appearance settings: provider visibility/order, font family/scale, separators, spacing, custom icons, accents, text color, and opacity.
  • Independent refresh: a short-lived Node collector fetches providers concurrently. Automatic refresh defaults to five minutes; the settings sanitizer enforces a five-minute minimum. Manual refresh is also available.
  • Failure handling: last-known-good usage survives transient failures and is marked stale. Claude honors rate-limit backoff; Codex supports a bounded OAuth refresh and a curl fallback.

Missing fields stay missing. An unlimited plan does not get an invented percentage; a provider without monthly usage does not get a fabricated monthly bar.

Project status

The source is public on GitHub. Package metadata currently says 2.0.0 (released 2026-10-02); the changelog tracks the full history back to 1.0.0.

There are no GitHub release assets or tags as of this documentation review. Install from source below. KDE Store publication is a separate, uncompleted release step. See the roadmap for candidate work, not promises.

Requirements

Requirement Notes
Linux with KDE Plasma 6 Package declares Plasma API minimum 6.0; not a GNOME, macOS, or Windows widget.
Node.js ≥20 The Plasma bridge invokes /usr/bin/node. A shell-only nvm/asdf installation is not sufficient.
npm and Git Needed to build from source. TypeScript is a pinned development dependency.
kpackagetool6 Installs the package as Plasma/Applet.
flock from util-linux Collector locking uses /usr/bin/flock.
zip Required; a missing tool or failed archive build is an error, not an unpacked-only success.
curl Used when Codex's normal HTTP request needs the fallback transport.
sqlite3 Needed at /usr/bin/sqlite3 for local Cursor session discovery; not needed when a usable environment fallback is used.

For development, also install Qt 6's qmllint, Qt Quick Test, Kirigami, and the Plasma QML modules. The current QML runner expects /usr/lib/qt6/bin/qmltestrunner; distro paths may differ.

Installation

git clone https://github.com/DarkoKuzmanovic/kuota.git
cd kuota
npm ci --ignore-scripts

Install the checked-out source:

scripts/install.sh

Both install and update rebuild from source every time, even when the version has not changed. They require a freshly produced, nonempty archive before calling the package tool. To build without installing, run npm run build:artifact.

The artifact checker runs the packaged collector in its own private temporary HOME/cache with an allowlisted environment. It does not pass your credentials, XDG paths, provider variables, or Node preload options to the collector. Each invocation has a two-second deadline and a 64 KiB output bound; temporary resources are removed on success or failure. These are offline checks, not a live-account smoke test. See the approved reliability amendment.

The build produces:

dist/artifact/kuota-v2.0.0/           unpacked Plasma package
dist/artifact/kuota-v2.0.0.plasmoid  verified installable archive

The installer installs or upgrades the package for your user. Open Plasma's Add Widgets dialog and add Kuota to a panel or the desktop. Click the panel summary to open the detail view.

Updating

  1. Pull the desired source revision: git pull --ff-only.
  2. Run npm ci --ignore-scripts.
  3. Run scripts/update.sh (always rebuilds before upgrading).
  4. Remove/re-add the widget or log out and back in to load the new code.

Build, check, and zip failures stop installation; previous same-version archives are not reused. New configuration keys require reloading the widget instance.

Uninstalling

scripts/uninstall.sh

This removes the package io.github.darkokuzmanovic.kuota and ~/.cache/kuota/. It does not delete Kuota's own logins (~/.config/kuota/credentials.json; remove them with kuota logout <provider> or delete the file) or edit Plasma's global configuration.

Providers and credentials

Kuota keeps its own logins in ~/.config/kuota/credentials.json ($XDG_CONFIG_HOME/kuota/; file mode 0600, directory 0700). It does not read Pi's auth.json. Sign in once per provider from a terminal with the bundled collector; a short alias helps:

alias kuota='node ~/.local/share/plasma/plasmoids/io.github.darkokuzmanovic.kuota/contents/code/collector/cli.js'
kuota login codex        # ChatGPT: open the printed URL, enter the code
kuota login grok         # SuperGrok / X Premium, same flow
kuota login kimi         # Kimi Code (or: kuota login kimi --api-key)
kuota login opencode     # paste an API key (hidden), or pipe it on stdin
kuota login commandcode  # paste an API key
kuota status             # which source each provider uses (never values)
kuota logout codex

Keys are never accepted as command arguments (they would show in ps). Never put tokens in widget settings, issues, or screenshots. Kuota renews its own Codex, Grok, and Kimi logins; it never refreshes or writes another tool's login. Codex device sign-in must be allowed for your ChatGPT account.

Provider Data available when returned by the provider Credential sources, in order
Claude Session/weekly utilization, reset times, model-specific windows and extra-usage facts. Claude Code's ~/.claude/.credentials.json (claudeAiOauth, needs user:profile scope). Read-only, never refreshed; sign in with Claude Code. Uses a fresh Kuota-owned cache before a live fetch.
Codex Primary/secondary usage windows, resets, plan/credit facts. kuota login codex; then the Codex CLI's ~/.codex/auth.json ($CODEX_HOME), read-only and never refreshed.
Grok Monthly credits and an optional weekly window. kuota login grok; GROK_CLI_OAUTH_TOKEN fallback.
Kimi Weekly and short-window usage, resets, concurrency facts. kuota login kimi (OAuth or --api-key); KIMI_API_KEY fallback.
Cursor Included-plan spend share, billing reset, membership and on-demand usage facts. Local Cursor state.vscdb session first, then CURSOR_SESSION_TOKEN.
OpenCode Go Hosted Go plan: rolling 5-hour, weekly, and monthly percentages with resets. Not arbitrary OpenCode/Zen/API spend. kuota login opencode (API key); OPENCODE_API_KEY fallback.
CommandCode Five-hour and optional weekly windows; monthly/purchased/free credit facts and optional plan name. kuota login commandcode (API key); COMMANDCODE_API_KEY fallback.

Provider limits matter: CommandCode exposes monthly credit allowances, not a monthly-used total; Kuota therefore has no monthly utilization window for it. Cursor uses an unofficial dashboard endpoint. These are client/account-facing surfaces, not a guarantee of a stable public API, and account plans can expose different fields.

Fallbacks are not overrides. File/local credentials generally take precedence. Unsafe files, malformed JSON, or malformed supported credential entries can fail closed instead of using the environment fallback. A variable exported in a terminal is not automatically inherited by the already-running Plasma session; do not put secrets in a launcher command to work around that.

Only Codex may write refreshed credentials back to the shared auth file, using an atomic, permission-preserving merge. Other providers are read-only credential consumers.

Configuration

Right-click Kuota and open its configuration dialog:

  • Providers: display/collection selection, display order, and compact usage-window choices for every provider except Cursor (one window only).
  • Appearance: display mode, font scale, separator, icon/label/value spacing, and countdown visibility.
  • Thresholds: refresh interval and caution/critical utilization levels.
  • Theming: optional fonts, icons, text colors, accents, and opacity. Native Plasma styling remains the default.

In this source revision, “Show and collect usage” controls both display and collection using the existing visibility setting. Disabled providers are excluded from future collector invocations, including credential discovery and requests. Disabling all providers leaves the empty view and launches no collector; it does not create a fresh observation. Re-enabling a provider requests a refresh. Reordering providers or changing appearance does not trigger collection.

Work already launched while a provider was enabled may finish. Selection changes clear the old snapshot and discard that in-flight result, then refresh only the latest selection once the existing run finishes or reaches its deadline. Multiple widget instances may select different subsets; cached records for other instances are preserved on disk but excluded from the current response.

Troubleshooting

Symptom Check
Widget missing or old code still shown Confirm installation used -t Plasma/Applet, rebuild the archive, then reload the widget or log out/in.
auth-needed Check the correct credential source for that provider and sign in again. Do not paste the auth file into a bug report.
Cursor login appears stale Confirm local Cursor login and /usr/bin/sqlite3. Kuota reads committed WAL updates; check DB/WAL/SHM access as described below.
stale Last successful data is retained. Check its timestamp; Claude may be in rate-limit backoff. Repeated Refresh clicks do not override that backoff.
error A provider may be unreachable or have changed its response; also check fixed runtime paths and the trusted local cache directory. Other providers can still update.
Settings seem ignored Reload after adding new config keys. Invalid values are sanitized to safe defaults; “Icons only” intentionally keeps the usage value.
Build has no .plasmoid file Install zip and resolve any compiler/checker/zip failure, then rebuild. An unpacked directory alone is not a successful build.
Shell Node works but widget fails Check /usr/bin/node; the bridge does not resolve your interactive shell's Node version manager.

Cursor local database access

Kuota opens ~/.config/Cursor/User/globalStorage/state.vscdb (then the lowercase cursor candidate) with SQLite's -readonly mode, without asserting that the database is immutable. This includes committed updates in an open WAL. Kuota does not copy, checkpoint, update, or persist the database or session token.

WAL access can require readable -wal/-shm sidecars and SQLite read-lock coordination. SHM lock bookkeeping is not promised to remain byte-identical; missing sidecars in a non-writable directory or unreadable files may prevent a safe read. Ordinary missing, busy, unreadable, or malformed local state still allows CURSOR_SESSION_TOKEN fallback. Cancellation, a two-second sqlite child deadline, or more than 64 KiB on either output stream stops discovery and does not proceed to another candidate, environment fallback, or provider request. Failures remain value-free. Do not attach databases, sidecars, or tokens to bug reports. Synthetic WAL tests cover freshness; a real-account re-login smoke is a separate, explicitly approved check.

Development

The project uses strict TypeScript, Node's built-in test runner, and Qt Quick Test. There are no runtime npm dependencies. Cursor's synthetic SQLite integration tests additionally require /usr/bin/sqlite3 and /usr/bin/python3 (Python 3 with its standard-library sqlite3 module).

Command Purpose
npm run typecheck Check TypeScript without emitting files.
npm test Compile and run collector, filesystem, lifecycle, and secret-safety tests.
npm run test:qml Run the offscreen Qt 6 UI/model/bridge suites.
npm run validate:plasma Check package metainfo and lint QML/JS.
npm run build:collector Build the runnable collector under dist/collector/.
npm run build:artifact Build/package the widget and run the artifact checker.

Run verification sequentially in a dedicated checkout with a disposable HOME and an explicit minimal environment (not just a different HOME). The artifact checker enforces its own isolation, but that is not a sandbox for arbitrary test code or npm tooling. Never run suites that share dist/ concurrently. Remove generated dist/ between gates when investigating stale-output failures. The QML suite is headless; it is not a substitute for a real panel/desktop smoke test.

The collector accepts no arguments (all providers) or one allowlisted --enabled-providers=<csv> argument. No credential arguments are accepted. For a no-provider serialization check inside an isolated verification home:

node dist/collector/cli.js --enabled-providers=

A normal successful invocation emits exactly one newline-terminated schema-v2 JSON document. Provider failures are records inside that document, not permission to emit raw responses or secrets.

plasmoid/           QML views, settings, and isolated collector bridge
collector/src/      Provider adapters, normalization, auth/cache I/O, redaction
collector/test/     Node collector tests
tests/              Synthetic fixtures, QML tests, security/lifecycle checks
scripts/            Build and local lifecycle commands
docs/               Architecture, approved specs, and review findings
dist/               Generated output; ignored by Git

Read AGENTS.md and PLAN.md before contributing. Product-visible changes require an approved design amendment. Add tests before changing provider behavior or security-sensitive persistence, and use synthetic fixtures rather than recorded credentials or raw account responses.

Architecture and security

Plasma views ↔ isolated CollectorBridge ↔ short-lived Node collector ↔ providers
                   normalized, validated JSON only

The collector owns all credentials and provider I/O. QML validates the complete snapshot before replacing its current data. Cross-process locking protects collection; cache writes use restrictive permissions; shared Codex auth updates preserve unrelated entries and file mode. Redaction and module-isolation tests protect these boundaries.

This is a local desktop integration, not a sandbox or an independent security audit. Keep auth files private. Before sharing diagnostics, remove account identifiers, tokens, environment values, and raw provider responses.

Further reading

License

MIT. Not affiliated with or endorsed by the listed providers.

About

KDE Plasma 6 widget for AI account usage: Claude, Codex, Grok, Kimi, Cursor, OpenCode Go, and CommandCode.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages