Skip to main content

Print your current-period GitHub Copilot spend and reset date.

Project description

copilot-spend

Find out what your Copilot habit actually costs.

A small Python CLI that reads your GitHub Copilot quota and prints your current-period spend in dollars and PRUs, plus when the period resets. Works against both github.com and GitHub Enterprise hosts.

How it works

flowchart TD
    Start([copilot-spend ...]) --> Cmd{subcommand?}

    Cmd -- login --> Host[prompt: github.com or GHE host]
    Host --> DeviceCode[POST /login/device/code]
    DeviceCode --> ShowCode[show user code + verification URL]
    ShowCode --> Poll[poll /login/oauth/access_token]
    Poll -- access_denied / expired --> LoginFail[/exit 2: login failed/]
    Poll -- ghu_ token --> Verify[verify token works<br/>GET /copilot_internal/user]
    Verify -- fail --> LoginFail
    Verify -- ok --> WriteAuth[write auth.json 0o600]
    WriteAuth --> LoginDone[/exit 0/]

    Cmd -- logout --> DeleteFiles[delete auth.json]
    DeleteFiles --> LogoutDone[/exit 0/]

    Cmd -- bare --> Native{native<br/>~/.config/copilot-spend/auth.json?}
    Native -- yes --> NativeBearer[bearer = ghu_ token]
    Native -- no --> Opencode{opencode<br/>~/.local/share/opencode/auth.json?}
    Opencode -- yes --> OpencodeBearer[bearer = gho_ token]
    Opencode -- no --> NoCreds[/exit 2: run copilot-spend login/]
    NativeBearer --> Quota[GET /copilot_internal/user with Bearer]
    OpencodeBearer --> Quota
    Quota -- 200 --> Print[/print spend + reset date<br/>exit 0/]
    Quota -- 401 / 403 --> AuthErr[/exit 2: re-authenticate/]
    Quota -- 404 --> NoSub[/exit 4: no Copilot quota/]
    Quota -- 5xx / timeout --> ApiErr[/exit 3: API error/]

The bare copilot-spend invocation, expanded as numbered steps:

  1. Resolves a GitHub Copilot token from the first source that exists, in this order:
    1. Native: ~/.config/copilot-spend/auth.json, created by running copilot-spend login.
    2. Opencode fallback: ~/.local/share/opencode/auth.json (keys github-copilot.access and github-copilot.enterpriseUrl), if opencode is installed.
  2. Uses the resolved token directly as the Bearer for the next step. Both source kinds work the same way: native gives a ghu_… GitHub App user-to-server token, opencode gives a gho_… OAuth App token, and /copilot_internal/user accepts either one directly.
  3. Calls GET /api/v3/copilot_internal/user on your GHE host, or GET https://api.github.com/copilot_internal/user if no enterprise host is configured.
  4. Computes the billable overage: billable_PRUs = max(0, consumed - entitlement), then dollars_owed = billable_PRUs × $0.04. The first entitlement PRUs each period are included with your plan and cost nothing.
  5. Prints a plain-text summary on stdout.

No background daemon. No history. No session-token cache. One HTTP request per run.

Requirements

  • Python 3.10 or newer
  • macOS or Linux
  • A GitHub Copilot token, obtained by either:
    • running copilot-spend login, or
    • having opencode installed and authenticated already

Install

# Option A: pipx (persistent, isolated)
pipx install copilot-spend

# Option B: pip (into your active environment or --user)
pip install copilot-spend

# Option C: uv tool (persistent, isolated)
uv tool install copilot-spend

# Option D: one-off run, no install
uvx copilot-spend
pipx run copilot-spend

Install from source

git clone https://github.com/nkootstra/copilot-spend.git
cd copilot-spend

pipx install .
# or:
uv tool install --from . copilot-spend
# or one-off:
uvx --from . copilot-spend

Usage

copilot-spend          # print current-period quota
copilot-spend --json   # same data as JSON (stable schema, jq-friendly)
copilot-spend whoami   # print active login, host, source, and plan
copilot-spend login    # authenticate via GitHub OAuth device flow
copilot-spend logout   # remove copilot-spend's stored credentials

copilot-spend login prompts for github.com or a GHE host, shows a device code with a URL to visit, then polls until you complete the flow in your browser. The new token is verified against /copilot_internal/user before anything gets persisted. Credentials land in ~/.config/copilot-spend/auth.json (mode 0o600). If you already have opencode authenticated, the bare copilot-spend command continues to work without login.

Example output (under your allowance):

GitHub Copilot - your-login (business)
  Used:      221 PRUs
  Allowance: $12.00  (300 PRUs included)
  Remaining: $3.16  (79 PRUs of free allowance left)
  Resets:    May 31, 2026 (in 15 days)

Example output (over your allowance — billable overage):

GitHub Copilot - your-login (business)
  Used:      4073 PRUs
  Allowance: $12.00  (300 PRUs included)
  Billable:  $150.92  (3773 PRUs over allowance at $0.04/PRU)
  Resets:    Jun 01, 2026 (in 16 days)

Flags: --help, --version, --json. Subcommands: login, logout, whoami.

JSON output (stable schema, null fields included):

{
  "billable_prus": 3773,
  "consumed_prus": 4073,
  "dollars_entitlement": 12.0,
  "dollars_free_remaining": 0.0,
  "dollars_owed": 150.92,
  "entitlement_prus": 300,
  "free_remaining_prus": 0,
  "login": "your-login",
  "plan": "business",
  "pru_price_usd": 0.04,
  "reset": "2026-06-01T00:00:00+00:00"
}

Environment variables

Variable Effect
COPILOT_SPEND_QUIET=1 Silence the permissive-perms warning when the auth file isn't 0o600.
COPILOT_SPEND_DEBUG=1 Re-raise unexpected exceptions with a full traceback; also emits a one-line diagnostic if the reset-date field can't be extracted.
COPILOT_SPEND_CONFIG_DIR Override the config directory (default: $XDG_CONFIG_HOME/copilot-spend or ~/.config/copilot-spend).

Exit codes

Code Meaning
0 Success
1 Unexpected error
2 Auth error (missing/invalid auth.json or token)
3 API error (network, timeout, 4xx/5xx)
4 No Copilot quota on the account

Switch to your own GitHub App

copilot-spend login runs the GitHub OAuth device flow against Microsoft's well-known VS Code Copilot GitHub App (Iv1.b507a08c87ecfe98). This is the same client ID used by every working third-party Copilot tool — copilot.vim, avante.nvim, LiteLLM, and others — because GitHub's session-token exchange endpoint (/copilot_internal/v2/token) only accepts tokens issued by a GitHub App, not by an OAuth App.

The trade-off: the GitHub consent screen during login says "GitHub for VS Code" rather than "copilot-spend", and you depend on Microsoft not rotating that app. To remove both, register your own GitHub App and swap the constant:

  1. Visit https://github.com/settings/apps and click New GitHub App. This must be a GitHub App, not an OAuth App — OAuth Apps issue gho_… tokens that the Copilot exchange endpoint rejects with 404.
  2. Set Homepage URL and Callback URL to anything (the device flow does not use them).
  3. Enable Device flow under "Identifying and authorizing users".
  4. Account permissions: none required beyond user identification. The read:user OAuth scope is enough.
  5. Note the resulting Client ID (starts with Iv23 or Iv1.).
  6. Replace the CLIENT_ID constant in src/copilot_spend/login.py with your new client ID.
  7. Rebuild/reinstall (pipx install --force . or uv tool install --force --from . copilot-spend).

After the swap, the consent screen shows your app's name and your copilot-spend install no longer breaks if Microsoft rotates Iv1.b507a08c87ecfe98.

Caveats

  • The PRU price is hardcoded at $0.04 (correct as of 2026-05). Update the constant in src/copilot_spend/quota.py if GitHub changes it.
  • v1 ships with VS Code's GitHub App ID Iv1.b507a08c87ecfe98 for the device flow. See "Switch to your own GitHub App" above to remove the dependency.
  • The billing model assumed: the first entitlement PRUs each period are included with your plan, and anything beyond that is billable at $0.04 per PRU. This matches observed behavior on a business plan. Org-level caps or contracts may change what you actually pay — treat the Billable figure as a personal estimate, not an invoice.
  • The reset-date field name in the Copilot API response is best-effort: copilot-spend tries the field names observed on a real response, plus a few defensive fallbacks, and prints next reset: unknown if none match. Adjust RESET_FIELD_CANDIDATES in quota.py if your response uses a different name.
  • The /copilot_internal/user endpoint is not a public, documented API. GitHub may change its shape at any time.

Development

python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

copilot_spend-0.2.0.tar.gz (31.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

copilot_spend-0.2.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file copilot_spend-0.2.0.tar.gz.

File metadata

  • Download URL: copilot_spend-0.2.0.tar.gz
  • Upload date:
  • Size: 31.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for copilot_spend-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a9cb7150ea4a20410704238c1c27c132598afe15bb5a4e0efedbb9fc63d50c00
MD5 201f97fe84d47eebebfdd3fdfe90b910
BLAKE2b-256 4f5216b9a1e6220e37abb8db4878d52cd84418651f608cf02d5c3d752fa287dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for copilot_spend-0.2.0.tar.gz:

Publisher: release.yml on nkootstra/copilot-spend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file copilot_spend-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: copilot_spend-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for copilot_spend-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7672827beaf8eff68172941a58069dd46c43c50e659cf41bf69c00cea623a0ae
MD5 9c66e30387849b00665d8b97ebc7140b
BLAKE2b-256 0bf4b2affd1720f6a192c2489175acf6ab17cc8788931ae909ed2793cbee9cad

See more details on using hashes here.

Provenance

The following attestation bundles were made for copilot_spend-0.2.0-py3-none-any.whl:

Publisher: release.yml on nkootstra/copilot-spend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page