Novels of Scotland, software, and the space between. Author of the Wardstane Chronicles, the DI Cormac Buchan Investigations, and the Pondlife novels.
ClaudeUse
GitHub · C#

ClaudeUse

Notes and tooling around using Claude Code.

View on GitHub

ClaudeUse — Claude Pro Usage Monitor

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:

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.

How it works

On an interval (PollSeconds, default 300):

  1. Reads the OAuth access token from ~/.claude/.credentials.json

(claudeAiOauth.accessToken).

  1. 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).

  1. Parses five_hour and seven_day (utilization, resets_at).
  2. Pushes Home Assistant sensors sensor.claude_5_hour_usage,

sensor.claude_5_hour_reset, sensor.claude_weekly_usage, sensor.claude_weekly_reset.

  1. Appends a row to the CSV.
  2. Writes a 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.

GitHub Copilot quota

If CopilotUsers is non-empty, each poll also does, per user:

  1. 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.

  1. Reads copilot_plan, quota_reset_date, and quota_snapshots for

premium_interactions, chat, completions — each with entitlement (-1 = unlimited), remaining, percent_remaining, overage_count, unlimited.

  1. Pushes Home Assistant sensors, all with the username in the entity id:

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.

_premium_remaining / _premium_percent_remaining / _premium_overage — each premium-request snapshot field broken out as its own sensor.

  1. Appends a row to copilot-usage.csv (next to the Claude CSV).
  2. Writes a 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 _.

Tokens

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>.

Configuration

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.

Secrets

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.

Build

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.)

Run

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.

LocalSystem has no user profile, so %USERPROFILE% won't resolve to your account. Either put absolute paths in App.config for CredentialsFile / LogFile, or change ProjectInstaller.cs to ServiceAccount.User and run it as yourself.

Files

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

Output

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.

View ClaudeUse on GitHub