1- # UsageTray
1+ # CodeFuel
22
3- A Windows system-tray widget that shows your remaining ** Claude Code ** and
4- ** OpenAI Codex ** usage at a glance — 5-hour session limits and weekly limits —
5- so you don't get cut off mid-task.
3+ A lightweight Windows system-tray widget that keeps your AI coding "fuel gauge"
4+ in view — the remaining ** Claude Code ** and ** OpenAI Codex ** usage limits plus
5+ your ** DeepSeek ** account balance — so you don't run dry mid-task.
66
7- It reuses the login credentials your Claude Code / Codex CLIs already store on
8- disk. No API keys to enter, zero configuration.
7+ For Claude and Codex it reuses the login credentials their CLIs already store on
8+ disk: no API keys to enter. DeepSeek uses a balance API key you supply.
9+
10+ > The interface is in Chinese (简体中文).
911
1012## What it shows
1113
12- - A tray icon with two horizontal bars: top = Claude (orange), bottom = Codex
13- (grey). Each bar tracks the provider's most-used limit; it turns red above 90%
14- and dims with a hatch pattern when that provider errors.
15- - Hover over the icon for a dark popup panel: a card per provider with a
16- progress bar, percentage, and reset countdown for each limit window. It
17- hides by itself once the cursor leaves the icon and the panel (left-click
18- also shows it, as a fallback).
19- - Right-click menu: ** Refresh now** , ** Start at login** (off by default),
20- ** Quit** .
14+ - ** Tray icon** — two stacked bars: top = Claude (orange), bottom = Codex
15+ (grey). Each bar tracks that provider's most-used limit, turns red above 90%,
16+ and dims with a hatch pattern when the provider errors.
17+ - ** Hover panel** — a dark popup with one card per provider:
18+ - Claude / Codex: a progress bar, percentage, and reset countdown for each
19+ limit window (5-hour session, weekly, etc.).
20+ - DeepSeek: account balance as plain text — total, topped-up, and granted —
21+ per currency. No progress bar (a balance has no natural ceiling) and no tray
22+ glyph.
23+
24+ The panel appears on hover and hides itself once the cursor leaves both the
25+ icon and the panel. Left-click also opens it as a fallback.
26+ - ** Right-click menu** — Refresh now · Start at login (off by default) · Quit.
27+
28+ Data is fetched on demand only — at startup, when you open the panel (throttled),
29+ and on manual refresh — so it never hammers the rate-limited usage endpoints.
2130
2231## Requirements
2332
2433- Windows 10/11 (64-bit) with the ** WebView2 runtime** (preinstalled on current
25- Windows 11; otherwise install from Microsoft's Evergreen WebView2 page).
26- - Logged-in Claude Code (` ~/.claude/.credentials.json ` ) and/or Codex
27- (` ~/.codex/auth.json ` ). If a credential is missing or expired, that card shows
28- a fix hint; the other provider keeps working.
29- - Python 3.11+ (only to run from source / build).
34+ Windows 11; otherwise install Microsoft's Evergreen WebView2 runtime).
35+ - For the Claude / Codex cards: a logged-in Claude Code
36+ (` ~/.claude/.credentials.json ` ) and/or Codex (` ~/.codex/auth.json ` ). If a
37+ credential is missing or expired, that card shows a fix hint; the others keep
38+ working.
39+ - For the DeepSeek card: a DeepSeek API key (see [ Configuration] ( #configuration ) ).
40+ - Python 3.11+ — only needed to run from source or build the EXE.
41+
42+ ## Install
43+
44+ Grab ` CodeFuel.exe ` from the [ Releases] ( ../../releases ) page and run it — it's a
45+ single self-contained executable, no installer.
3046
31- ## Run from source
47+ Or run from source:
3248
3349``` powershell
3450python -m pip install -r requirements.txt
@@ -40,61 +56,65 @@ python -m usagetray --cli
4056python -m usagetray
4157```
4258
59+ ## Configuration
60+
61+ A config file is created on first run at ` %APPDATA%\UsageTray\config.json ` :
62+
63+ ``` json
64+ {
65+ "min_fetch_gap_seconds" : 60 ,
66+ "providers" : { "claude" : true , "codex" : true , "deepseek" : true },
67+ "deepseek_api_key" : " "
68+ }
69+ ```
70+
71+ - ` min_fetch_gap_seconds ` — when you open the panel, a provider is re-fetched at
72+ most once per this many seconds (manual refresh bypasses it).
73+ - ` providers ` — toggle individual cards on/off.
74+ - ` deepseek_api_key ` — your DeepSeek balance key. Leave empty to fall back to the
75+ ` DEEPSEEK_API_KEY ` environment variable. With no key, the DeepSeek card shows a
76+ hint and the other providers are unaffected.
77+
78+ Logs live next to the config at ` %APPDATA%\UsageTray\usagetray.log ` (rotating,
79+ 1 MB × 3). Credentials and tokens are never logged. A named mutex prevents a
80+ second instance from launching.
81+
4382## How it works
4483
4584```
4685providers/ --fetch()--> poller (daemon thread) --writes--> state (locked cache)
4786 claude.py |
4887 codex.py tray (pystray) panel (pywebview)
88+ deepseek.py
4989```
5090
51- - ** providers/** read local credentials and call each tool's private usage
52- endpoint. ` fetch() ` never raises — on failure it returns a snapshot whose
53- ` error ` carries a human-readable fix hint.
54- - Claude: ` GET https://api.anthropic.com/api/oauth/usage `
91+ - ** providers/** read local credentials (or an API key) and call each tool's
92+ usage endpoint. ` fetch() ` never raises — on failure it returns a snapshot
93+ whose ` error ` carries a human-readable fix hint.
94+ - ** Claude** — ` GET https://api.anthropic.com/api/oauth/usage `
5595 (` anthropic-beta: oauth-2025-04-20 ` ). On a 401 it attempts one standard
5696 OAuth refresh using the local ` refreshToken ` ; the refreshed token is kept in
5797 memory only and ** never written back** to your credentials file.
58- - Codex: ` GET https://chatgpt.com/backend-api/wham/usage `
98+ - ** Codex** — ` GET https://chatgpt.com/backend-api/wham/usage `
5999 (` Authorization: Bearer ` , ` ChatGPT-Account-Id ` ).
60- - DeepSeek: ` GET https://api.deepseek.com/user/balance `
61- (` Authorization: Bearer ` ). Key comes from config.json ` deepseek_api_key ` ,
62- falling back to the ` DEEPSEEK_API_KEY ` env var. Shows account balance
63- (total / topped-up / granted) as text, not a progress bar; no tray glyph.
64- - ** poller** fetches on demand only (no periodic polling): once at startup,
65- when the panel is shown (throttled to one fetch per provider per
66- ` min_fetch_gap_seconds ` ), and on manual refresh (bypasses the throttle).
67- One provider failing never blocks the other.
100+ - ** DeepSeek** — ` GET https://api.deepseek.com/user/balance `
101+ (` Authorization: Bearer ` ).
102+ - ** poller** fetches on demand only (no periodic polling): once at startup, when
103+ the panel is shown (throttled per ` min_fetch_gap_seconds ` ), and on manual
104+ refresh. One provider failing never blocks the others.
68105- ** state** is a thread-safe snapshot cache; the UI only reads from it.
69106
70- ## Configuration
71-
72- ` %APPDATA%\UsageTray\config.json ` (created on first run):
73-
74- ``` json
75- {
76- "min_fetch_gap_seconds" : 60 ,
77- "providers" : { "claude" : true , "codex" : true , "deepseek" : true },
78- "deepseek_api_key" : " "
79- }
80- ```
81-
82- ` deepseek_api_key ` 留空时回退到环境变量 ` DEEPSEEK_API_KEY ` 。
83-
84- Logs: ` %APPDATA%\UsageTray\usagetray.log ` (rotating, 1 MB × 3). Tokens are never
85- logged. A named mutex prevents a second instance from launching.
86-
87107## Build a single EXE
88108
89109``` powershell
90110python -m pip install pyinstaller
91- python -m PyInstaller --noconfirm UsageTray .spec
92- # -> dist\UsageTray .exe
111+ python -m PyInstaller --noconfirm CodeFuel .spec
112+ # -> dist\CodeFuel .exe
93113```
94114
95- The ` .spec ` bundles ` panel.html ` as data and builds a windowed (no console)
96- single-file executable. The autostart registry entry points at the EXE when
97- frozen, or at ` pythonw -m usagetray ` when run from source.
115+ The ` .spec ` bundles ` panel.html ` as data and produces a windowed (no console)
116+ single-file executable. The "Start at login" entry points at the EXE when frozen,
117+ or at ` pythonw -m usagetray ` when run from source.
98118
99119## Tests
100120
@@ -103,5 +123,10 @@ python -m pytest -q
103123```
104124
105125Covers each provider (real-response parsing via captured fixtures, missing
106- credentials, 401 + refresh, timeouts, field changes), the poller (failure
107- isolation, backoff, manual-refresh wake), and config loading.
126+ credentials, 401 + refresh, rate limits, timeouts, field changes), the data
127+ model, the poller (on-demand fetch, throttling, failure isolation), and config
128+ loading.
129+
130+ ## License
131+
132+ [ MIT] ( LICENSE ) © 2026 libing
0 commit comments