- Python 47.8%
- QML 46.9%
- Shell 5.1%
- Makefile 0.2%
| backend | ||
| contents | ||
| tests | ||
| updater | ||
| .gitignore | ||
| build-release.sh | ||
| install.sh | ||
| Makefile | ||
| metadata.json | ||
| README.md | ||
| uninstall.sh | ||
AI Quota Plasma widget
Plasma 6 taskbar widget showing provider quota pages for Codex, OpenCode Go, and Claude Code.
Features
- Compact view: one chip per provider, with independently selected quota windows and one provider icon.
- Popup: isolated, horizontally swipeable Codex, OpenCode Go, and Claude Code pages behind icon-only tabs (names in tooltips).
- Every provider page shows all available quota windows in a responsive vertical list.
- Inline switches show or hide each individual quota window in the taskbar.
- Codex page shows optional 5-hour and weekly windows, reset countdowns, account email, plan type, and refresh.
- OpenCode Go page scrapes live rolling, weekly, and monthly dashboard windows.
- Claude Code page shows 5-hour session and weekly limits, reset countdowns, plan type, and (popup only) cloud credit balance and extra usage status.
- Refresh on load, every 15 minutes, when the popup opens (if data is over a minute old), or with Refresh button on live providers.
- Weekly pace card on Codex and Claude Code pages compares usage against elapsed window time.
- Updates tab shows installed/latest versions, last check time, status, and verified install action.
- Provider descriptors and reusable pages support future adapters.
- No third-party Python dependencies. No credentials are stored by this project.
Requirements
- KDE Plasma 6 (targeted and tested against Plasma 6.7 APIs)
- Python 3.10+
codexCLI with app-server support- user systemd
kpackagetool6JetBrainsMono Nerd Fontfor update glyphs
Codex must already be authenticated. Backend calls codex app-server --stdio, sends initialize, then reads account/read and account/rateLimits/read.
Claude Code must already be logged in with a Pro or Max subscription. Backend reads the OAuth access token from ~/.claude/.credentials.json at refresh time, sends it only to https://api.anthropic.com/api/oauth/usage, and never refreshes, writes, returns, or logs it.
OpenCode Go uses the existing dashboard session entry in ~/.pi/agent/auth.json:
{
"quota-status": {
"opencode-go": {
"workspaceId": "...",
"authCookie": "..."
}
}
}
The backend reads this file at refresh time, sends the cookie only to https://opencode.ai/workspace/<workspaceId>/go, and never returns or logs either credential.
Install
Do not run this script as root. It installs widget package and backend under user-local paths, then starts a user service.
./install.sh
Add AI Quota to panel through Plasma widget chooser. Backend listens only on 127.0.0.1:17934.
Automatic updates
Installation enables quota-widget-update.timer. It checks daily with up to one hour of randomized delay.
Updater downloads:
https://apache.tsbprodesk.co.uk/files/programs/quota-widget-latest.tar.gzhttps://apache.tsbprodesk.co.uk/files/programs/hashes/quota-widget-latest.tar.gz.sha256
Release archive may contain project files directly or inside one top-level directory. It must contain metadata.json, install.sh, and app ID org.kde.plasma.quota. Increment KPlugin.Version using MAJOR.MINOR.PATCH for every release.
Generate both upload-ready files from repository root:
./build-release.sh
Outputs mirror server paths:
dist/programs/quota-widget-latest.tar.gz
dist/programs/hashes/quota-widget-latest.tar.gz.sha256
Updater verifies SHA-256, rejects unsafe archive paths and downgrades, then runs release install.sh. Check manually or inspect logs:
quota-widget-update
systemctl --user status quota-widget-update.timer
journalctl --user -u quota-widget-update.service
SHA-256 protects transfer integrity but does not protect against compromise of server hosting both archive and checksum.
Uninstall
./uninstall.sh
Uninstall removes widget, backend, updater, wrappers, user services, timer, and updater state. It does not modify Codex login state or files.
Backend contract
GET http://127.0.0.1:17934/v1/quota?provider=codex returns one JSON document:
{
"provider": "codex",
"ok": true,
"updatedAt": 1700000000,
"account": {"email": "user@example.test", "planType": "pro"},
"quota": {
"id": "weekly",
"label": "Weekly",
"available": true,
"usedPercent": 20,
"remainingPercent": 80,
"windowDurationMins": 10080,
"resetsAt": 1700600000
},
"quotas": [
{
"id": "fiveHour",
"label": "5-Hour",
"available": true,
"usedPercent": 10,
"remainingPercent": 90,
"windowDurationMins": 300,
"resetsAt": 1700018000
},
{
"id": "weekly",
"label": "Weekly",
"available": true,
"usedPercent": 20,
"remainingPercent": 80,
"windowDurationMins": 10080,
"resetsAt": 1700600000
}
],
"error": null
}
Codex keeps quota as weekly compatibility alias. Missing windows remain unavailable rather than receiving inferred usage values.
GET http://127.0.0.1:17934/v1/quota?provider=opencode-go returns a quotas array containing rolling, weekly, and monthly windows with remaining percentages and reset timestamps.
GET http://127.0.0.1:17934/v1/quota?provider=claude returns a quotas array containing session (5-hour) and weekly windows.
Updates tab sends POST /v1/update with internal request header, then polls GET /v1/update/status. Status includes installed version, latest checked version, and last successful check time. Backend starts quota-widget-update.service; downloaded releases retain existing SHA-256 verification.
Errors keep the same shape with ok: false and {code, message}. Backend never emits subprocess stderr, dashboard HTML, auth cookies, workspace IDs, or protocol payloads. Unknown routes return 404. HTTP server binds loopback only.
Development
make test
make check
Tests use static protocol-shaped messages; they never access real account data.
Limitations
- OpenCode Go scraping depends on its server-rendered hydration field names (
rollingUsage,weeklyUsage, andmonthlyUsage). Dashboard changes may require parser updates. - OpenCode Go dashboard cookies expire; refresh credentials in
~/.pi/agent/auth.jsonwhen the widget reports an invalid session. - Reset countdowns depend on Codex supplying
windowDurationMinsandresetsAt. 5-hour and weekly selection uses duration, not primary/secondary position. - Claude Code usage uses an undocumented OAuth endpoint and may change. Expired tokens are not refreshed by the backend; run
claudeonce to refresh them. - Service uses fixed local port
17934; change port in install script, service template, and QML endpoint together if port conflicts. - Existing installed widget with same ID is replaced by
kpackagetool6during install.
Credits
OpenCode Go dashboard request and hydration-field discovery were informed by @mjfuertesf/pi-quota-status. This widget uses its own Python adapter and normalized multi-window response.