Skip to main content

CloudCost CLI for Terraform cost estimates and GitHub pull request cost automation.

Project description

CloudCost AI

CloudCost AI is a developer-first FinOps MVP. It has two mechanisms:

  1. An AI spend proxy powered by LiteLLM.
  2. A GitHub App webhook that estimates Terraform cost deltas in pull requests with Infracost.

The landing page is served from index.html; the working backend is in backend/app.

Get Started

The first-run path is modeled around a local CLI estimate, then GitHub automation:

.\.venv\Scripts\python -m pip install -e .
cloudcost go

Run cloudcost go from a Terraform project directory. It runs the local estimate, then opens the GitHub App manifest install flow with the required webhook, events, and permissions already filled in. If a team only wants the local estimate, cloudcost still works by itself. Power users can also run cloudcost setup, cloudcost doctor, cloudcost connect-github, or cloudcost analyze --plan tfplan.json directly.

When the package is published, users should install it with:

pipx install cloudcost-cli
cloudcost go

Publishing notes are in docs/publishing-pypi.md.

The signed-in dashboard sidebar links to /get-started, a docs-style first-run guide with macOS, Windows, and Linux command tabs that update the CLI install, setup, Terraform, CI, and GitHub steps. The left docs rail links to styled HTML docs for CloudCost CLI, VPS install, and pricing API reference.

Cloudflare Pages Landing Page

For a free public early-access page, deploy the static pages plus the Pages Functions:

  • functions/api/waitlist.js
  • functions/api/auth/*
  • functions/api/dashboard/summary.js
  • package.json

Use npm run build and set the Cloudflare Pages output directory to dist; the build script copies index.html, assets/, docs/, /login, /signup, /dashboard, /get-started, and /tester-dashboard.

Set DATABASE_URL, AUTH_SECRET, RESEND_API_KEY, and FROM_EMAIL in Cloudflare Pages environment variables. The Functions store early-access emails, users, OTPs, and browser sessions in Neon, and send Resend confirmations without running the Python backend.

See docs/cloudflare-pages-waitlist.md.

One-Click VPS Path

For a customer-facing install, use the VPS bundle instead of the local debug path.

Prerequisites:

  • Ubuntu VPS with ports 80 and 443 open
  • A domain pointed at the VPS
  • Docker, or approval for the bootstrap script to install Docker
  • A pricing mode:
    • Recommended: CloudCost hosted pricing key
    • Advanced: Infracost API key for syncing a self-hosted pricing database

Run:

git clone YOUR_REPO_URL cloudcost-ai
cd cloudcost-ai
bash scripts/bootstrap-vps.sh

The script generates local secrets, creates .env, starts Caddy HTTPS, backend, LiteLLM, and Postgres. If the customer chooses strict self-hosted pricing, it also initializes and runs the local Infracost pricing API. It then prints:

  • Dashboard: https://YOUR_DOMAIN/dashboard
  • Tester runbook: https://YOUR_DOMAIN/tester-dashboard
  • GitHub install page: https://YOUR_DOMAIN/install/github
  • Webhook URL: https://YOUR_DOMAIN/api/github/webhook

Open the GitHub install page and click Install on GitHub. GitHub creates a customer-owned GitHub App from CloudCost's manifest and redirects back with the App ID, webhook secret, and private key. CloudCost stores those on the VPS automatically.

After setup, run:

bash scripts/doctor-vps.sh

This path is the intended customer install path. The longer local setup below remains for development and debugging.

Architecture

Browser
  -> FastAPI backend
     -> static landing page
     -> waitlist endpoint
     -> GitHub webhook endpoint
     -> LiteLLM admin wrapper
     -> metadata-only usage ingest

LLM clients
  -> LiteLLM proxy :4000
     -> OpenAI / Anthropic / other providers
     -> metadata-only callback
     -> FastAPI /api/llm/usage

GitHub pull_request webhook
  -> HMAC validation
  -> installation access token
  -> locate Terraform plan JSON
  -> Infracost Plan JSON API
  -> upsert PR comment

Quick Start

  1. Create local environment config:
Copy-Item .env.example .env
  1. Fill .env with:
  • DATABASE_URL, preferably a pooled Neon Postgres URL with sslmode=require
  • GITHUB_APP_ID or GITHUB_CLIENT_ID
  • GITHUB_PRIVATE_KEY_PATH
  • GITHUB_WEBHOOK_SECRET
  • INFRACOST_API_KEY
  • LITELLM_MASTER_KEY
  • at least one provider key, such as OPENAI_API_KEY

Put the downloaded GitHub App private key at secrets/github-app-private-key.pem. Docker Compose mounts ./secrets into the backend container as /app/secrets.

DATABASE_URL is shared by LiteLLM and the backend. LiteLLM uses it for virtual keys and spend/auth state; the backend creates cloudcost_waitlist, cloudcost_usage_events, cloudcost_users, cloudcost_email_otps, and cloudcost_sessions tables for app data. Set APP_DATABASE_URL if you want those app tables in a separate database.

The waitlist endpoint accepts only an email address, stores one row per email, and uses data/waitlist.jsonl only when no Postgres URL is configured. Set SMTP_HOST and SMTP_FROM_EMAIL if you want waitlist signups to receive a confirmation email.

For app signups, set AUTH_SECRET to a long random value. New accounts verify a mail OTP before /dashboard creates a session.

  1. Start the stack:
docker compose up --build

If Docker Desktop is not installed, run the backend and LiteLLM locally instead:

.\.venv\Scripts\python -m pip install -e ".[dev]"
.\.venv\Scripts\python -m pip install "litellm[proxy]" prisma
.\scripts\start-litellm-local.ps1

In a second terminal:

.\.venv\Scripts\python -m uvicorn backend.app.main:app --reload --port 8000

For the local no-Docker path, set LITELLM_BASE_URL=http://127.0.0.1:4000 in .env.

  1. Open:
  • Landing page: http://localhost:8000
  • Sign in: http://localhost:8000/login
  • Sign up: http://localhost:8000/signup
  • Dashboard: http://localhost:8000/dashboard
  • Get started: http://localhost:8000/get-started
  • Tester runbook: http://localhost:8000/tester-dashboard
  • Backend health: http://localhost:8000/healthz
  • Mechanism map: http://localhost:8000/api/mechanism
  • LiteLLM proxy: http://localhost:4000

GitHub App Setup

Register a GitHub App with:

  • Webhook URL: https://YOUR_DOMAIN/api/github/webhook
  • Webhook secret: same value as GITHUB_WEBHOOK_SECRET
  • Subscribe to only pull_request
  • Repository permissions:
    • Contents: read
    • Pull requests: read and write
    • Issues: write
    • Metadata: read

The backend handles opened, reopened, synchronize, and ready_for_review pull request actions.

Terraform Plan JSON

The MVP looks for one of these files in the pull request files first, then in the repository tree at the PR head SHA:

  • plan.json
  • tfplan.json
  • terraform-plan.json
  • infracost-plan.json
  • files ending in .tfplan.json or .plan.json

Generate a compatible file with Terraform:

terraform init
terraform plan -out tfplan.binary
terraform show -json tfplan.binary > plan.json

When found, the backend runs the local Infracost CLI against the plan JSON, parses diffTotalMonthlyCost, and creates or updates one CloudCost AI pull request comment. In the default self-hosted setup, the plan JSON stays inside your backend runtime; the CLI only talks to your Cloud Pricing API for price lookups.

Self-Hosted Infracost

The default project mode is:

INFRACOST_MODE=cli
INFRACOST_CLI_PATH=infracost
INFRACOST_PRICING_API_ENDPOINT=http://127.0.0.1:4001

That means CloudCost AI does not call the hosted Infracost Plan JSON API. Instead:

  1. You self-host the Infracost Cloud Pricing API.
  2. The backend runs infracost breakdown --path plan.json --format json.
  3. The Infracost CLI requests prices from INFRACOST_PRICING_API_ENDPOINT.
  4. The backend comments the result on the pull request.

For local Windows development, install the Infracost CLI and make sure infracost is on PATH. For Docker builds, the backend image installs the CLI automatically.

See /docs/pricing-api.html for the full setup path.

LiteLLM Spend Proxy

LiteLLM requires DATABASE_URL for persistent virtual keys, budgets, spend logs, and auth state. With Neon, use the pooled connection string from the Neon dashboard:

DATABASE_URL=postgresql://USER:PASSWORD@HOST/neondb?sslmode=require&channel_binding=require

Create a virtual key through CloudCost AI:

Invoke-RestMethod -Method Post http://localhost:8000/api/llm/keys `
  -ContentType 'application/json' `
  -Body '{
    "user_id": "ada@example.com",
    "team_id": "platform",
    "models": ["gpt-5-mini"],
    "max_budget": 10,
    "budget_duration": "30d",
    "metadata": {"service": "billing"}
  }'

Use the returned key against LiteLLM:

$env:OPENAI_API_KEY = "sk-returned-virtual-key"

Point OpenAI-compatible clients at:

http://localhost:4000/v1

On the VPS bundle, Caddy exposes LiteLLM through the same HTTPS origin:

https://YOUR_DOMAIN/llm/v1

LiteLLM enforces the budgets and forwards metadata-only usage records to /api/llm/usage. The custom callback deliberately omits prompts, messages, responses, choices, and completions.

Local Development

Install dependencies:

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"

Run tests:

pytest

Run the backend without Docker:

uvicorn backend.app.main:app --reload --port 8000

Important Limits

This is an MVP scaffold, not a production billing system yet.

  • Real GitHub, Infracost, and LLM provider credentials are required for end-to-end live calls.
  • The JSONL stores in data/ are for local validation; replace them with a database before production.
  • For production GitHub traffic, put the backend behind HTTPS and keep the webhook secret/private key out of the repo.
  • For production LiteLLM, pin image versions, rotate master keys, and use a managed Postgres database.

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

cloudcost_cli-0.1.0.tar.gz (40.0 kB view details)

Uploaded Source

Built Distribution

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

cloudcost_cli-0.1.0-py3-none-any.whl (39.7 kB view details)

Uploaded Python 3

File details

Details for the file cloudcost_cli-0.1.0.tar.gz.

File metadata

  • Download URL: cloudcost_cli-0.1.0.tar.gz
  • Upload date:
  • Size: 40.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for cloudcost_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 85b7161440642dcba641bbb9851c04ac0b9457186221a6f1e89b91f65b7d5054
MD5 3211f276724f4fcc7b3f0985e384e15e
BLAKE2b-256 abe821c63e30be1317707a30c9f79afb0ebe0e12b278e8d9b3221195c419649c

See more details on using hashes here.

File details

Details for the file cloudcost_cli-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: cloudcost_cli-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for cloudcost_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6575840fa3c7e94620a6643cdb5783bcb7c2de1088d5d085fca4d9f163711cb4
MD5 611187ca3bf0a2dba8aa1aa5077e015c
BLAKE2b-256 9284dd3f41b9b8508bdacd2d2bfb5da8d339d6b1a11ce00a0266f74e25a17626

See more details on using hashes here.

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