Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ plasmashell --replace &
```
local_stats.py ──→ JSON ──→ main.qml (updateClaude)
gemini_local_stats.py ──→ JSON ──→ main.qml (updateGeminiCli)
antigravity_stats.py ──→ JSON ──→ main.qml (updateAntigravity)
opencode_stats.py ──→ JSON ──→ main.qml (updateOpenCode)
copilot_stats.py ──→ JSON ──→ main.qml (updateCopilot)
kiro_stats.py ──→ JSON ──→ main.qml (updateKiro)
pi_stats.py ──→ JSON ──→ main.qml (updatePi)
gemini_stats.py ──→ JSON ──→ main.qml (updateGemini)
/proc/pid/io ──→ grep ──→ main.qml (instantRate / gcliInstantRate / piInstantRate)
/proc/pid/io ──→ grep ──→ main.qml (instantRate / gcliInstantRate / piInstantRate / ocInstantRate)
```

`main.qml` uses `Plasma5Support.DataSource` with engine `"executable"` to run the Python scripts on a timer (`refreshInterval`, default 300s). The scripts output JSON to stdout which gets parsed and mapped to QML properties.
Expand All @@ -64,13 +68,22 @@ gemini_stats.py ──→ JSON ──→ main.qml (updateGemini)
- `sessions/*/*.jsonl` → per-message token usage (input, output, cacheRead, cacheWrite) and costs
- Detects active processes via `pgrep -x pi` (parent + child PIDs)

- **`copilot_stats.py`** — Parses `~/.copilot/session-store.db`:
- Session and turn totals (today/week/month/total)
- Active sessions from recent turns for better accuracy
- Recent session list with cwd metadata

- **`kiro_stats.py`** — Parses `~/.kiro/` and Kiro workspace storage:
- Version/running state, powers, extensions
- Credit usage and recent workspace directories

- **`gemini_stats.py`** — Uses `countTokens` endpoint (free, no quota impact) to check API availability

- **`formatters.js`** — Formatting helpers: `formatTokens()`, `formatCost()`, `formatDuration()`, `tierLabel()`, `shortModel()`

### UI Components (`contents/ui/`)

- **`main.qml`** — Root `PlasmoidItem` with compact/full representations, tabs (Summary/Claude/Gemini CLI/Antigravity/Pi/OpenCode/Gemini API), all state properties, I/O polling
- **`main.qml`** — Root `PlasmoidItem` with compact/full representations, tabs (Summary/Claude/Gemini CLI/Antigravity/Pi/OpenCode/Copilot CLI/Kiro/Gemini API), all state properties, I/O polling
- **`ClaudeTab.qml`** — Claude dashboard with quota rings, tachometer, charts, sessions
- **`GeminiCliTab.qml`** — Gemini CLI dashboard (mirrors Claude layout)
- **`PiTab.qml`** — Pi dashboard with dual quota rings, tachometer, costs, charts, sessions
Expand Down
169 changes: 58 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,161 +1,108 @@
# OhMyToken

**Real-time token dashboard for AI coding assistants** -- a KDE Plasma 6 widget that tracks usage, quotas, throughput, costs, and sessions across multiple AI tools, right from your desktop panel.
Real-time KDE Plasma 6 widget for monitoring AI coding tools in one dashboard: quotas, throughput, sessions, trends, and costs.

<p align="center">
<img src="screenshots/main.png" alt="OhMyToken — KDE Plasma 6 AI token dashboard" width="480"/>
<img src="screenshots/main.png" alt="OhMyToken widget" width="460"/>
</p>

## Supported Tools
## Tabs and data sources

| Tool | Data Source | Real-time | Quotas |
|------|-----------|-----------|--------|
| **Claude Code** | `~/.claude/` telemetry, sessions, JSONL | `/proc/pid/io` 1s polling | Session window + daily (auto-detected tier) |
| **Gemini CLI** | `~/.gemini/` chat sessions | `/proc/pid/io` child worker polling | Requests/day by tier |
| **Pi** | `~/.pi/agent/sessions/` JSONL | `/proc/pid/io` polling | Token + cost tracking |
| **OpenCode** | `~/.local/share/opencode/` SQLite DB | `/proc/pid/io` polling | Token tracking |
| **Antigravity IDE** | Language server local API | Status endpoint polling | Prompt + Flow credits |
| **Gemini API** | `countTokens` endpoint (free) | -- | Rate limits (requests + tokens) |

Each tool can be individually enabled or disabled. The widget gracefully handles tools that aren't installed or aren't running.
| Tab | Source | Highlights |
|---|---|---|
| Summary | Aggregated from enabled providers | Total tokens, combined throughput, usage-ranked provider rows, and total + normalized comparison charts with consistent per-service colors |
| Claude Code | `~/.claude/` telemetry/sessions/history | Session-window quotas, token/cost trends, live activity |
| Gemini CLI | `~/.gemini/` chats/settings | Request quota, token trends, active-session polling |
| Pi | `~/.pi/agent/` sessions/settings | Token + cost tracking, prompts, model/provider breakdown |
| OpenCode | `~/.local/share/opencode/opencode.db` | Token usage, sessions, models, throughput |
| Antigravity | Local language-server API | Credits, model/session activity, token trends |
| Copilot CLI | `~/.copilot/session-store.db` | Turns/sessions totals, active sessions from recent turns |
| Kiro | `~/.kiro/` + `~/.config/Kiro/User/workspaceStorage` | Running status, powers/extensions, credits, recent directories |
| Gemini API | `countTokens` endpoint | Request/token remaining limits per model |

## Features

### Live Tachometer
Car-style animated gauge with rotating needle, engine vibration jitter, three color zones (green/yellow/red), and adaptive max scale. Responds in real-time to streaming activity via `/proc/pid/io` polling at 1-second intervals.

### Dual Quota Rings
Concentric input/output progress rings with color-coded thresholds -- green under 70%, yellow 70-90%, red above 90%. Session window quotas on the left, daily totals on the right.

### Dashboard Layout
Session Ring | Tachometer | Daily Ring side by side, with session countdown timer below. Falls back to a standalone tachometer when quota data isn't available.

### Hourly & Daily Charts
- **Hourly**: 12-hour smooth Catmull-Rom curves with adaptive bucket aggregation (5/10/15/20/30/60/120 min)
- **Daily**: 8-day stacked bar chart (input + output)

### Active Sessions
Live session cards with token counts, duration, message count, and pulsing glow animation that reflects streaming activity per-session.

### Model Breakdown
Per-model token usage with proportional bars and cost estimates.

### Summary Tab
Aggregated view across all enabled providers -- total tokens today/week/month, combined sessions, merged throughput rates.

### Panel Indicator
Two modes for the system tray:
- **Quota Ring** -- mini session progress ring with percentage label
- **Mini Tachometer** -- animated gauge showing real-time throughput across all active tools

### Cost Tracking
Estimated API costs (weekly and total) with configurable monthly budget threshold.

<p align="center">
<img src="screenshots/dashboard.png" alt="Dashboard with tachometer and dual quota rings" width="420"/>
</p>
- Unified multi-tab dashboard with configurable per-service visibility
- Sticky popup pin + adjustable popup height
- Live tachometer from `/proc/<pid>/io` polling
- 12h and daily charts where service data exists
- Meter fallback behavior for low-activity windows
- Clickable local paths/directories (opens file manager)
- Compact panel indicator with selectable service/stat target
- Copilot active-session counting from recent turn activity

## Installation

### From .plasmoid file

```bash
bash build.sh
kpackagetool6 -t Plasma/Applet -i ohmytoken.plasmoid
```

### From GitHub Releases

Download the latest `ohmytoken.plasmoid` from [Releases](https://github.com/postadelmaga/plasmoid-ohmytoken/releases), then:
## Upgrade

```bash
kpackagetool6 -t Plasma/Applet -i ohmytoken.plasmoid
bash build.sh
kpackagetool6 -t Plasma/Applet -u ohmytoken.plasmoid
```

### Upgrade
## Remove

```bash
bash build.sh
kpackagetool6 -t Plasma/Applet -u ohmytoken.plasmoid
kpackagetool6 -t Plasma/Applet -r ohmytoken
```

### Development (symlink)
## Development (symlink)

```bash
ln -s /path/to/plasmoid-ohmytoken/ohmytoken ~/.local/share/plasma/plasmoids/ohmytoken
```

Changes to source files are live immediately -- just reload the widget.
Edits under `ohmytoken/` are live immediately when using a symlinked install.

## Configuration

Right-click the widget and select **Configure...**.

### Services

| Setting | Default | Description |
|---------|---------|-------------|
| Claude Code | On | Monitor `~/.claude/` telemetry and sessions |
| Gemini CLI | On | Monitor `~/.gemini/` chat sessions |
| Pi | On | Monitor `~/.pi/agent/` sessions and usage |
| OpenCode | On | Monitor `~/.local/share/opencode/` SQLite database |
| Antigravity | On | Monitor via language server API (auto-discovered) |
| Gemini API | Off | Requires API key -- get one at [ai.google.dev](https://ai.google.dev) |

### Display

| Setting | Default | Description |
|---------|---------|-------------|
| Refresh interval | 300s | Data polling interval (60--900s) |
| Panel indicator | Ring | Quota ring or mini tachometer in panel mode |
| Show costs | On | Display estimated API costs |
| Monthly budget | $100 | Budget threshold for cost tracking |
Right-click the widget and choose **Configure...**.

### Claude Limits
Key options:
- Service toggles (including Pi, Copilot CLI, Kiro)
- Refresh interval
- Popup height
- Pin popup open
- Compact indicator style + target service/stat
- Cost display and monthly budget
- Claude daily limit overrides (`0 = auto`)
- Gemini API key

| Setting | Default | Description |
|---------|---------|-------------|
| Daily input limit | Auto | Override auto-detected tier limit (0 = auto) |
| Daily output limit | Auto | Override auto-detected tier limit (0 = auto) |

Tier limits are auto-detected from `~/.claude/.credentials.json`:

| Tier | Input/day | Output/day |
|------|----------|------------|
| Max 5x | 1.665B | 166.5M |
| Max | 300M | 30M |
| Team | 200M | 20M |
| Pro | 100M | 10M |

Gemini CLI tier is detected from `~/.gemini/settings.json` (Free: 1000, Standard: 1500, Enterprise: 2000 requests/day).
Default config template files:
- `ohmytoken/contents/config/main.xml`
- `ohmytoken/contents/ui/configGeneral.qml`

## Architecture

```
local_stats.py ----> JSON ----> main.qml (Claude)
gemini_local_stats.py ----> JSON ----> main.qml (Gemini CLI)
pi_stats.py ----> JSON ----> main.qml (Pi)
opencode_stats.py ----> JSON ----> main.qml (OpenCode)
antigravity_stats.py ----> JSON ----> main.qml (Antigravity)
gemini_stats.py ----> JSON ----> main.qml (Gemini API)
/proc/pid/io ----> grep ----> main.qml (tachometers)
```text
local_stats.py -> Claude tab
gemini_local_stats.py -> Gemini CLI tab
pi_stats.py -> Pi tab
opencode_stats.py -> OpenCode tab
antigravity_stats.py -> Antigravity tab
copilot_stats.py -> Copilot tab
kiro_stats.py -> Kiro tab
gemini_stats.py -> Gemini API tab
/proc/pid/io polling -> live tachometer activity
```

- **Backend**: Python scripts parse local data files, SQLite databases, and local APIs. Output JSON to stdout.
- **Real-time**: `/proc/pid/io` rchar polling at 1s for Claude, Gemini CLI, Pi, and OpenCode processes. Language server endpoint polling for Antigravity.
- **Rendering**: Split Canvas layers (static background / dynamic arcs) with GPU-composited needle rotation for minimal CPU impact. Jitter animation only runs during active streaming.
## Build and packaging notes

- `build.sh` packages from `ohmytoken/` with `metadata.json` and `contents/` at archive root.
- Temporary/debug files are excluded from the distributable archive.

## Requirements

- KDE Plasma 6
- Python 3
- Linux (requires `/proc` filesystem for real-time I/O monitoring)
- One or more of: Claude Code, Gemini CLI, Pi, OpenCode, Antigravity IDE
- Linux (`/proc` required for live I/O activity polling)
- At least one supported tool/account for the tabs you enable

## License

GPL-3.0+

## Credits

Built with [Claude Code](https://claude.ai/code)
8 changes: 6 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ PLASMOID_FILE="ohmytoken.plasmoid"

echo "Creating ${PLASMOID_FILE}..."
rm -f "${PLASMOID_FILE}"
zip -r "${PLASMOID_FILE}" "${WIDGET_DIR}/" \
-x "${WIDGET_DIR}/.git/*"
# Package contents and metadata at archive root (required by kpackagetool6).
(
cd "${WIDGET_DIR}" || exit 1
zip -r "../${PLASMOID_FILE}" . \
-x ".git/*" "*/__pycache__/*" "*.pyc" "*.pyo" "*.backup" "*~"
)

if [ -f "${PLASMOID_FILE}" ]; then
echo "Created ${PLASMOID_FILE} successfully!"
Expand Down
Loading