How the Token Budget handles credentials and data access for each provider.
| Claude Code | Z.ai | GitHub Copilot | Qwen Code | |
|---|---|---|---|---|
| Credential source | ~/.claude/.credentials.json (auto) |
~/.local/share/opencode/auth.json (auto) |
gh auth token or manual config |
None (local-only) |
| Manual setup needed | No | No | Only if gh CLI not installed |
No |
| API endpoints called | api.anthropic.com/api/oauth/usage |
api.z.ai/api/monitor/usage/quota/limit |
api.github.com/user, api.github.com/users/{user}/settings/billing/premium_request/usage |
None |
| Local files read | ~/.claude/widget-data.json |
~/.local/share/opencode/storage/message/**/*.json |
None | ~/.qwen/projects/*/chats/*.jsonl |
| Token refresh | No (see limitations) | No | No | N/A |
| Graceful degradation | Shows disk-cached data with simulated resets | Widget shows "no data" | Widget shows "no data" | Widget shows "no data" if no JSONL files found |
Source: %USERPROFILE%\.claude\.credentials.json
The widget reads the claudeAiOauth.accessToken field from this file. This file is created and managed by Claude Code itself — no manual setup is required.
| What | Path / URL | Purpose |
|---|---|---|
| Live session data | %USERPROFILE%\.claude\widget-data.json |
Current model, cost, token counts, context window usage |
| OAuth usage API | GET https://api.anthropic.com/api/oauth/usage |
Rate-limit utilization (5-hour, 7-day windows) |
| Disk cache | %USERPROFILE%\.claude\oauth-usage-cache.json |
Persisted last-known API response (written by widget) |
The API request includes headers anthropic-beta: oauth-2025-04-20 and User-Agent: claude-code/2.0.37.
None beyond what Claude Code already provisions. The OAuth token is created during normal Claude Code login.
If the credentials file is missing or the token has expired, the widget falls back to its disk-cached usage data. Cached rate-limit percentages are adjusted by simulating resets (if a limit's reset time has passed, its utilization is zeroed out). The widget continues showing data this way until Claude Code is opened and refreshes the token.
- No token refresh. The widget cannot refresh expired OAuth tokens because it doesn't have the
client_id(only Claude Code does). After a cold start or long idle period, data may be stale until Claude Code runs again. widget-data.jsonstaleness. If the file hasn't been updated in 5 minutes, the widget treats it as absent (Claude Code not running).- API cache. Successful API responses are cached for 30 seconds in memory and persisted to disk.
Source: %USERPROFILE%\.local\share\opencode\auth.json
The widget reads the API key from the zai-coding-plan.key field, falling back to zai.key. This file is created by the opencode CLI during login — no manual setup is required.
| What | Path / URL | Purpose |
|---|---|---|
| Message files | %USERPROFILE%\.local\share\opencode\storage\message\<session>\*.json |
Token counts per assistant message (input, output, reasoning, cache) |
| Quota API | GET https://api.z.ai/api/monitor/usage/quota/limit |
Rate-limit utilization (5-hour rolling, weekly) |
The API request uses Authorization: Bearer <API_KEY>.
None beyond what the opencode CLI already provisions. The API key is created during normal opencode login.
If the auth file is missing or the key is invalid, the quota API call silently fails and the widget shows local token data only (no rate-limit bars). Local message parsing works regardless of API credentials.
- No token refresh. If the API key is revoked or expires, the widget cannot re-authenticate. The user must re-login via the opencode CLI.
- API cache. Successful API responses are cached for 30 seconds.
Priority order:
ghCLI — runsgh auth tokento read the token from the GitHub CLI's credential store. Cached for the lifetime of the widget process.- Manual config file —
%USERPROFILE%\.config\token-budget\copilot.jsonwith{"token": "ghp_..."}.
| What | Path / URL | Purpose |
|---|---|---|
| Copilot quota | GET https://api.github.com/copilot_internal/user |
Premium request quota/usage for the authenticated user |
The request uses Authorization: Bearer <token>.
The GitHub token needs the user scope (or manage_billing:copilot). If using gh CLI, ensure you've authenticated with sufficient scopes:
gh auth login --scopes user- Create a GitHub Personal Access Token with
userscope. - Save it:
// %USERPROFILE%\.config\token-budget\copilot.json {"token": "ghp_your_token_here"}
If no token is found (neither gh CLI nor config file), or the token lacks the required scope, the widget shows no data. There is no fallback cache — the widget remains empty until a valid token is available.
ghCLI token is cached once. The token retrieved fromgh auth tokenis cached for the process lifetime. If the user re-authenticatesghwith a different account, the widget must be restarted to pick it up.- API cache. Successful API responses are cached for 30 seconds.
- Quota is hardcoded. The Pro plan limit of 300 premium requests/month is hardcoded. Other plan tiers are not yet supported.
None. The Qwen Code provider is entirely local — it reads JSONL session files from disk and makes no API calls.
| What | Path / URL | Purpose |
|---|---|---|
| Session files | %USERPROFILE%\.qwen\projects\<project>\chats\<session>.jsonl |
Token counts per assistant message (input, output, cache, reasoning) |
None. The widget only reads files created by Qwen Code CLI.
There is no DashScope API for Coding Plan quota. The widget estimates rate-limit utilization by counting assistant messages in rolling time windows:
| Window | Limit | Reset |
|---|---|---|
| 5-hour rolling | 1,200 requests | Oldest request exits window |
| Weekly | 9,000 requests | Monday 00:00 UTC+8 |
| Monthly | 18,000 requests | 1st of month 00:00 UTC+8 |
If no JSONL files exist under ~/.qwen/projects/, the widget shows no data. There is no fallback — the widget remains empty until Qwen Code creates session files.
- No API verification. Quota limits are hardcoded estimates for the Coding Plan Lite tier. Actual server-side limits may differ.
- Request counting only. Quota utilization is based on message count, not token count, since that is what the plan limits appear to gate on.
All outbound HTTP requests are funneled through a single class: HttpGateway (src/TokenBudget.Core/HttpGateway.cs). No other code in the project creates HttpClient instances or sends HTTP requests directly.
The gateway maintains a hardcoded allowlist of exactly 3 endpoints:
| Endpoint | URL |
|---|---|
AnthropicOAuthUsage |
https://api.anthropic.com/api/oauth/usage |
ZaiQuotaLimit |
https://api.z.ai/api/monitor/usage/quota/limit |
GitHubCopilotUsage |
https://api.github.com/copilot_internal/user |
The Qwen Code provider makes no network requests — it is entirely local.
Adding a new endpoint requires adding to the ApiEndpoint enum and the URL dictionary in HttpGateway.cs. This makes it easy to audit all network access in a single file.
- No telemetry. The widget does not send any data to third parties. All API calls go directly to the respective provider (Anthropic, Z.ai, GitHub).
- No credential storage. The widget does not store or copy credentials. It reads them from existing tool configuration files at runtime. The one exception is the disk cache at
~/.claude/oauth-usage-cache.json, which stores API response data (utilization percentages and reset times), not credentials. - MSIX sandbox. When installed via MSIX, the widget runs under package identity with standard sandbox isolation.
- Polling only when active. API calls and file reads only occur while the Widgets Board is open and the widget is visible. No background polling.
- Read-only access. The widget never writes to provider credential files. The only file it writes is its own OAuth usage cache.