A Windows service (.NET Framework 4.7.2) that polls the Anthropic OAuth usage API and reports your Claude Pro 5-hour / weekly utilization to:
NOTIFY: line when 5-hour usage crosses 80% / 90% / 100%The same poll also tracks the GitHub Copilot premium-request / chat / completions quota for one or more GitHub users, including enterprise-billed seats (see GitHub Copilot quota below).
It is a port of claude-usage.ps1. The main difference: the PowerShell script raises a Windows toast; a service runs in session 0 and can't show toasts, so threshold notifications are written to the service log file instead. The app does no Windows event-log I/O, so it never needs elevation for that.
On an interval (PollSeconds, default 300):
~/.claude/.credentials.json (claudeAiOauth.accessToken).
GET https://api.anthropic.com/api/oauth/usage with the Bearer / anthropic-beta: oauth-2025-04-20 / User-Agent: claude-code/2.0 headers (TLS 1.2, 30s timeout).
five_hour and seven_day (utilization, resets_at).sensor.claude_5_hour_usage, sensor.claude_5_hour_reset, sensor.claude_weekly_usage, sensor.claude_weekly_reset.
NOTIFY: line to the service log for any newly-crossed 5-hour threshold. The triggered set resets whenever resets_at changes (new 5-hour window).
Poll errors are logged and the loop continues. Polls never overlap.
If CopilotUsers is non-empty, each poll also does, per user:
GET {GitHubApiBase}/copilot_internal/user with Authorization: token <token>, Accept: application/json, and Editor-Version / Editor-Plugin-Version / X-GitHub-Api-Version headers (defaults vscode/1.96.2, copilot-chat/0.26.7, 2025-04-01). This is the endpoint the editor plugins and the Copilot SDK's account.getQuota() use — there is no separately documented REST route, but it returns the authenticated user's own entitlement, so it works for individual, business and enterprise-billed seats. CopilotUsers entries are just labels; the data is for whichever account the matching CopilotToken belongs to.
copilot_plan, quota_reset_date, and quota_snapshots for premium_interactions, chat, completions — each with entitlement (-1 = unlimited), remaining, percent_remaining, overage_count, unlimited.
sensor.copilot_<user>_premium / _chat / _completions — state = percent of the entitlement used (0 when unlimited); the full snapshot (entitlement / used / remaining / percent_remaining / overage_count / overage_permitted / unlimited / plan / login / resets) is in the attributes.
sensor.copilot_<user>_premium_entitlement / _premium_used / _premium_remaining / _premium_percent_remaining / _premium_overage — each premium-request snapshot field broken out as its own sensor.
sensor.copilot_<user>_quota_reset — state = quota_reset_date.copilot-usage.csv (next to the Claude CSV).NOTIFY: Copilot premium N% log line for each newly-crossed Thresholds level on premium-request usage. The triggered set resets when quota_reset_date changes.
Each user is independent — one user's token or API error is logged and the others still run. <user> in sensor names is the username lower-cased with non-alphanumerics turned into _.
Each CopilotToken.<username> must be that user's own GitHub token for an account with an active Copilot seat — a classic PAT or an OAuth (device-flow) token; the token auth scheme is used and no special scope is required. Fine-grained PATs are usually rejected by this endpoint. Put them in secrets.config:
<add key="CopilotToken.RaymondJStone" value="ghp_… or gho_…" />
For a GitHub Enterprise Cloud enterprise with a dedicated subdomain, set GitHubApiBase to https://api.<slug>.ghe.com; for GitHub Enterprise Server use https://api.<host>.
Non-secret settings are in App.config (appSettings):
| Key | Default | Meaning |
|---|---|---|
CredentialsFile |
%USERPROFILE%\.claude\.credentials.json |
Claude OAuth credentials file |
PollSeconds |
300 |
Poll interval in seconds |
LogFile |
%USERPROFILE%\claude-usage.csv |
CSV history path (claude-usage-service.log sits next to it) |
Thresholds |
80,90,100 |
5-hour utilization levels that raise a notification (also used for Copilot premium-quota notifications) |
HomeAssistantUrl |
(empty) | Home Assistant base URL — set in secrets.config |
HomeAssistantToken |
(empty) | Home Assistant long-lived token — set in secrets.config |
CopilotUsers |
(empty) | Comma-separated labels, one per Copilot token to poll; empty disables it |
CopilotToken.<username> |
(empty) | That user's own GitHub token (classic PAT / OAuth) — set in secrets.config |
GitHubApiBase |
https://api.github.com |
API host (https://api.<slug>.ghe.com for GHEC subdomain, https://api.<host> for GHES) |
GitHubApiVersion |
2025-04-01 |
X-GitHub-Api-Version header value |
CopilotEditorVersion |
vscode/1.96.2 |
Editor-Version header |
CopilotPluginVersion |
copilot-chat/0.26.7 |
Editor-Plugin-Version header |
Environment variables in path values (e.g. %USERPROFILE%) are expanded.
HomeAssistantUrl, HomeAssistantToken and the CopilotToken.<username> PATs live in secrets.config, which is git-ignored. App.config pulls it in via <appSettings file="secrets.config">; if the file is missing it is silently ignored and the Home Assistant push is skipped. Keys defined in secrets.config override the empty ones in App.config.
copy secrets.config.example secrets.config
# edit secrets.config and paste your Home Assistant long-lived access token
secrets.config is copied next to ClaudeUse.exe.config at build time.
dotnet build ClaudeUse.csproj -c Release
or open ClaudeUse.slnx in Visual Studio 2022+. (The legacy Framework64\v4.0.30319\MSBuild.exe won't work — it's a C# 5 compiler.)
As a console app (for testing — logs to stdout):
bin\Debug\ClaudeUse.exe --console
Runs the same poll loop; press Enter to stop.
As a Windows service:
InstallUtil.exe bin\Release\ClaudeUse.exe :: install
sc start ClaudeUsageMonitor
sc stop ClaudeUsageMonitor
InstallUtil.exe /u bin\Release\ClaudeUse.exe :: uninstall
The installer registers the service as ClaudeUsageMonitor ("Claude Pro Usage Monitor"), start type Automatic, account LocalSystem.
LocalSystemhas no user profile, so%USERPROFILE%won't resolve to your account. Either put absolute paths inApp.configforCredentialsFile/LogFile, or changeProjectInstaller.cstoServiceAccount.Userand run it as yourself.
| File | |
|---|---|
UsageMonitorService.cs |
The service — poll loop, Anthropic usage + GitHub Copilot quota calls, HA push, CSV, notifications |
ProjectInstaller.cs |
InstallUtil registration |
Program.cs |
Service host / --console mode |
App.config |
Non-secret settings |
secrets.config |
Home Assistant URL + token, Copilot PATs (git-ignored) |
secrets.config.example |
Template for secrets.config |
Claude CSV (LogFile):
Timestamp,FiveHourPercent,FiveHourReset,WeeklyPercent,WeeklyReset
"2026-08-29 08:00:00","42","2026-08-29 11:15:00","17","2026-09-02 00:00:00"
Copilot CSV (copilot-usage.csv, next to the Claude CSV):
Timestamp,User,Login,Plan,PremiumEntitlement,PremiumUsed,PremiumRemaining,PremiumPercentUsed,ChatPercentUsed,CompletionsPercentUsed,QuotaReset
"2026-09-03 08:00:00","RaymondJStone","RaymondJStone","individual","300","1","299","0.2","","","2026-10-01"
Service log (claude-usage-service.log, next to the CSV): timestamped lines for each poll, HA push result, threshold notification, Copilot per-user summary, and error.