Skip to content
mrusmePublic

About

Check your cloud spending from the CLI, from Waybar, and from the macOS menu bar! (https://tty.fail/mrus/cloudcash)

Topics

Resources

Stars

22 stars

Watchers

1 watching

Forks

Repository files navigation

Cloudcash

SEGV LICENSE

Check your cloud spending from the CLI, from Waybar, and from the macOS menu bar!

Waybar

Cloudcash on Waybar

macOS menu bar

Cloudcash on macOS

Supported cloud services

  • Alibaba Cloud (have no account ¯\(ツ)/¯ )
  • Amazon Web Services
  • Claude (subscription usage, see note below)
  • Codex (subscription usage, see note below)
  • DigitalOcean
  • GitHub
  • Google Cloud Platform (have no account ¯\(ツ)/¯ )
  • Heroku (have no account ¯\(ツ)/¯ )
  • Hetzner Cloud (calculated locally, see note below)
  • Microsoft Azure (have no account ¯\(ツ)/¯ )
  • Oracle Cloud (have no account ¯\(ツ)/¯ )
  • Render (no billing API yet)
  • Vultr
  • suggest a new one!

Build

go build .

Configuration

Only add the services that you want to use and delete all the others:

cat ~/.config/cloudcash.toml
[Waybar]
Pango = "  {{.Name}} <span color='#aaaaaa'>{{.Status.CurrentCharges}} {{.Status.Currency}}</span> [<span color='#aaaaaa'>{{.Status.PreviousCharges}} {{.Status.Currency}}</span>]"
PangoJoiner = " · "

[Menu]
Template = "{{.Name}} {{.Status.CurrentCharges}} {{.Status.Currency}}"
Joiner = " · "
IsDefault = false

[Service]

[Service.Vultr]
APIKey = "XXXX"

[Service.DigitalOcean]
APIKey = "XXXX"

[Service.AWS]
AWSAccessKeyID = "AAAA"
AWSSecretAccessKey = "XXXX"
Region = "us-east-1"

[Service.GitHub]
APIKey = "XXXX"
Users = [
  "mrusme"
]
Orgs = [ 
  "paper-street-soap-co"
]

[Service.Claude]
Enabled = true

[Service.Codex]
Enabled = true

[Service.Hetzner]
APIKey = "XXXX"

Alternative paths for configuration file:

  • /etc/cloudcash.toml
  • $XDG_CONFIG_HOME/cloudcash.toml
  • $HOME/.config/cloudcash.toml
  • $HOME/cloudcash.toml
  • ./cloudcash.toml

Every option can also be set through an environment variable, e.g. CLOUDCASH_SERVICE_VULTR_APIKEY.

Secrets don't have to be stored in the file. APIKeyCommand, AWSSecretAccessKeyCommand and OAuthTokenCommand run a command through sh -c (cmd on Windows) and use the first line of its output. The plain option takes precedence when both are set:

[Service.Vultr]
APIKeyCommand = "pass show vultr"

Note regarding AWS: CurrentCharges and PreviousCharges cover the current and the previous month, rounded to two decimals. Each refresh makes one Cost Explorer request, which AWS bills at $0.01.

Note regarding GitHub: You can specify multiple users/orgs, which are queried and added up to one total amount. The amount is the netAmount of the current month's billing usage report, covering all metered products. A fine-grained token needs the Plan user permission (read) for Users and the Administration organization permission (read) for Orgs.

Note regarding Claude: This reports your Claude subscription (Pro/Max) usage, not Claude API billing. CurrentCharges shows the usage credits spent so far, in the currency of your extra usage. It also exposes {{.Status.SessionUsage}} (current 5-hour session) and {{.Status.WeeklyUsage}} (current 7-day window), both as percentages of your plan's quota, and {{.Status.SessionResetsIn}} and {{.Status.WeeklyResetsIn}}, the seconds until each window resets.

By default the OAuth token is read from ~/.claude/.credentials.json, which the Claude Code CLI maintains and refreshes. Override the location with CredentialsFile, or pass a token directly with OAuthToken:

[Service.Claude]
Enabled = true
# CredentialsFile = "/home/you/.claude/.credentials.json"
# OAuthToken = "XXXX"
# UsageOnly = true

On a fixed plan without usage-based billing, set UsageOnly = true to show only the percentages. It applies to the text output and the default Pango template, and a custom Pango can check {{if not .UsageOnly}} to do the same.

Be aware that Anthropic offers no documented API for subscription usage. This uses the same undocumented endpoint that Claude Code's own /usage command queries, so it may break without notice. Anthropic's documented usage and cost APIs cover API organizations only, require an Admin API key, and are not available to individual accounts.

Note regarding Codex: This reports your ChatGPT subscription usage, not OpenAI API billing, and works the same way the Claude provider does. It fills {{.Status.SessionUsage}} and {{.Status.SessionResetsIn}} from the 5-hour window and {{.Status.WeeklyUsage}} and {{.Status.WeeklyResetsIn}} from the weekly one. OpenAI reports credits remaining rather than credits spent, so the figure ends up in {{.Status.AccountBalance}} and CurrentCharges stays at zero. Accounts on an unlimited plan report no balance.

The OAuth token and account ID are read from $CODEX_HOME/auth.json, falling back to ~/.codex/auth.json, which the Codex CLI maintains and refreshes:

[Service.Codex]
Enabled = true
# CredentialsFile = "/home/you/.codex/auth.json"
# OAuthToken = "XXXX"
# AccountID = "XXXX"
# UsageOnly = true

The same caveat as with Claude applies, only more so: OpenAI publishes no API for subscription usage, and this queries the endpoint the Codex CLI polls for its /status output. Newer Codex versions can keep credentials in the system keyring instead of auth.json, in which case there is no token to read and you have to set OAuthToken yourself. OpenAI's documented costs and usage APIs cover platform spending only and need an admin key.

Note regarding Hetzner: Hetzner Cloud has no billing endpoint, so charges are calculated locally. The hcloud-go library supplies both the price list and the resources on the account. Each resource is billed from the later of the first of the month or its own creation date, at the hourly rate, and never beyond the monthly price, which is how Hetzner itself caps it.

Servers, load balancers, volumes, primary IPs and floating IPs are counted, including backup surcharges and outgoing traffic past what a server or load balancer includes. Prices are net. Set Gross = true for VAT-inclusive ones:

[Service.Hetzner]
APIKey = "XXXX"
# Gross = true

This is an estimate rather than an invoice, because only resources that still exist are visible through the API, so anything deleted earlier in the month is missing from the total, and snapshots, images and additional features are not counted at all.

Waybar

The Pango template used in the -waybar-pango output is used per service, separated by the PangoJoiner string. To make it clear, if Pango is <span>{{.Name}}</span> and PangoJoiner is - then the output for two services (e.g. Vultr and AWS) would be:

<span>Vultr</span> - <span>AWS</span>

The Pango configuration uses Go's text/template. {{.Status.Currency}} contains the ISO 4217 code of the amounts, such as USD or EUR, and .UsageOnly is true for services with UsageOnly set. The duration function formats a countdown, e.g. {{duration .Status.SessionResetsIn}} renders as 2h13m. Pango defaults to:

Pango = "{{.Name}}{{if not .UsageOnly}} {{.Status.CurrentCharges}} {{.Status.Currency}}{{end}}"

PangoUsage is a second template, appended to Pango, that renders only for services reporting quota usage, currently Claude and Codex. Pango applies to every service, so putting {{.Status.SessionUsage}} in it would show 0% next to Vultr, AWS and everyone else. It defaults to:

PangoUsage = " [<span color='#aaaaaa'>{{.Status.SessionUsage}}%</span> · <span color='#aaaaaa'>{{.Status.WeeklyUsage}}%</span>]"

Set it to "" to leave the percentages out of the Waybar output.

macOS menu bar

The Template in Menu is what is used to render the macOS menu bar widget. As with the Waybar output, the template is per service, separated by the Joiner string. Unlike the Waybar.Pango configuration, Menu.Template does not support Pango, but it can include things like Emojis. It defaults to {{.Name}} {{.Status.CurrentCharges}} {{.Status.Currency}}.

To always run in menu mode, set Menu.IsDefault to true.

Use

CLI (text)

cloudcash

CLI (JSON)

cloudcash -json

Claude and Codex statuses also contain session_resets_at and weekly_resets_at, and the seconds left in session_resets_in and weekly_resets_in.

Waybar

rg -NA6 'cloudcash":'  ~/.config/waybar/config
"custom/cloudcash": {
  "format": "{}",
  "return-type": "json",
  "exec": "/usr/local/bin/cloudcash -waybar-pango",
  "on-click": "",
  "interval": 3600
},

macOS menu bar

cloudcash -menu-mode

Alternatively set Menu.IsDefault to true in configuration.

Errors

Errors are printed to stderr, with text and JSON output exiting with 1 when a service fails. -waybar-pango leaves failed services out and exits with 0, because Waybar hides a module when its command fails. Configuration and template errors exit with 1 in every mode, as does -menu-mode outside macOS.

Cache

The last successful result of each service is stored in cloudcash/status.json under $XDG_CACHE_HOME or ~/.cache. On macOS the directory is ~/Library/Caches. When a service is rate limited, meaning HTTP 429 or AWS throttling, its cached value is shown and a notice is printed to stderr. Deleting the file is safe.

About

Check your cloud spending from the CLI, from Waybar, and from the macOS menu bar! (https://tty.fail/mrus/cloudcash)

Topics

Resources

Stars

22 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages