- name
- stack-budget
- description
- Estimate the monthly RUNNING cost of any codebase (hosting, database, email, analytics, LLM, queues, storage, servers) from its dependencies, and return an interactive React calculator with traffic/user inputs and a per-service "migrate to" picker that finds the cheapest or self-hosted stack. Use when the user asks what a repo costs to run, for a stack/infra budget, hosting cost estimate, or how to cut a project's running costs — for the current folder, a local path, or any GitHub repo (owner/repo or URL, public or private). Read-only: never commits, pushes or opens PRs.
# Stack budget
Turns a repository into a running-cost calculator. The output is one self-contained HTML page
(React via CDN) that shows: the paid services the code depends on, a monthly bill driven by
traffic / users / email volume / AI usage, and a "migrate to" choice for every service with the
new total and savings. It estimates **running** costs only, not the cost of building the product.
`SKILL_DIR` below means the folder containing this file (usually `~/.claude/skills/stack-budget`).
## Hard rules
- **Read-only on the target repo.** Never commit, push, branch, open a PR, or write files inside
the repo. All working files go to a temp folder; the report goes to `~/stack-budgets/` unless the
user names another place (if that place is inside the repo, `build_report.py` adds it to
`.git/info/exclude` so it can never be committed).
- **Never open real secrets.** Do not read `.env`, `.env.local`, `.env.production` or any file that
holds values. The scanner reads only key names from `*.example` / `*.sample` / `*.template` env files.
- Prices live in `assets/engine.js`. Do not invent prices in the report. A service the engine
cannot price becomes a `custom` slot with a flat monthly figure and a note saying where the
number came from (user, README, or "enter your plan price").
## Step 1 — Resolve the target
The user passes one argument (or none):
| Input | Action |
|---|---|
| nothing or `.` | the current working directory |
| a local path | that folder |
| `owner/repo` or `https://github.com/owner/repo[...]` | shallow clone into a temp dir (below) |
Clone remote repos read-only into a fresh temp folder:
```bash
WORK="$(mktemp -d -t stack-budget-XXXX)"
gh repo clone owner/repo "$WORK/repo" -- --depth 1 --quiet \
|| git clone --depth 1 --quiet "https://github.com/owner/repo.git" "$WORK/repo"
```
`gh` uses the user's GitHub login, so private repos work. If both fail, say whether it looks like
a missing `gh auth login`, a typo, or no access, and stop. For a local target use
`WORK="$(mktemp -d -t stack-budget-XXXX)"` for working files only.
## Step 2 — Scan
```bash
python3 "$SKILL_DIR/scripts/scan_repo.py" <repo_dir> --out "$WORK/stack.json" [--repo owner/repo]
```
It parses every manifest (package.json incl. Bun/pnpm workspace catalogs, requirements, pyproject,
go.mod, Cargo.toml, Gemfile, composer.json), host files (vercel.json, wrangler.toml, netlify.toml,
fly.toml, Dockerfile, compose files), compose images and example-env key names, then maps packages
to cost slots with `scripts/rules.json`. It prints one line per slot.
## Step 3 — Review and correct stack.json (this is the part that needs judgment)
The scanner is a first pass. Before building, check each slot against the code and fix
`$WORK/stack.json` (schema in `references/stack-schema.md`):
1. **Confirm the current provider.** Read the deploy evidence: README "deploy/self-host" sections,
compose files under `install/`, `deploy/`, `infra/` (production) vs `local/`, `dev/` (local only),
CI deploy workflows in `.github/workflows`, Dockerfiles, `vercel.json`/`wrangler.toml`, and which
env key names the code reads (`grep -rhoE "process\.env\.[A-Z_]+|os\.environ\[.?[A-Z_]+"`).
Example: `S3_ENDPOINT` means any S3-compatible store, so R2 is a valid current choice;
`SMTP_HOST` means a relay (SES assumed) unless the code delivers on port 25 itself.
2. **Drop false positives**: dev-only matches (evidence says "only dev dependencies"), test
tooling, or a library that is imported but unused in production code.
3. **Add what the rules missed**: any SaaS SDK or API the code calls (grep for `https://api.`,
`new <Vendor>Client`, `_API_KEY`) becomes a slot. Use an engine category if one fits
(hosting, analytics, llm, email, database, redis, storage, compute, observability), else
`"category": "other", "current": "custom", "flat": <number>, "note": "<where the number comes from>"`.
4. **Fix sides and labels**: `"side": "fe"` only for things billed by page traffic (hosting,
browser analytics, hosted auth); everything server-side is `"be"`. Give multi-app repos a clear
package line, e.g. `"next · 3 apps: web, docs, dashboard"`.
5. **Write 2–5 `notes`** a reader needs: what the repo's own self-host path runs, assumptions you
made, fees that are per-transaction rather than monthly.
6. Optional: if the README or the user states real scale (users, emails/month), put it in
`presets.growth` (e.g. `{"users": 20000, "sent": 3000000}`).
7. Set `"title"` to `<Product name> Stack Budget`.
Keep the review proportional: a small repo needs a minute, a monorepo a careful pass over its
production compose/deploy files. Do not read the whole codebase line by line.
## Step 4 — Build the report
```bash
python3 "$SKILL_DIR/scripts/build_report.py" "$WORK/stack.json" [--out <path.html>]
```
Default output: `~/stack-budgets/<owner-repo>-budget.html`. It also prints a text summary (current
vs cheapest stack at Launch / Growth / Scale presets) using the same engine as the page; needs
`node` for the summary only.
## Step 5 — Return it
- If an `Artifact` tool is available (claude.ai), publish the HTML file as an artifact.
- Otherwise open it: `open <file>` (macOS), `xdg-open <file>` (Linux), `start <file>` (Windows),
and give the user the absolute path.
- Reply in a few lines: the slots found, current monthly total at the Growth preset, the
cheapest-stack total, and the two or three moves that save the most (from the summary).
Mention trade-offs the page flags (self-hosted MTA deliverability, free-tier caps, data loss
from analytics caps). Do not paste the HTML.
- Delete the temp clone: `rm -rf "$WORK"`.
## The calculator, briefly
- Usage inputs only show for categories the repo uses. Presets: Launch, Growth, Scale.
- Each row: current provider and cost, a "Migrate to" select, the new cost and the delta.
- "Pick cheapest stack" chooses the lowest-cost option per row and skips options whose hard
free-tier limit the usage exceeds. Self-hosted options add capacity to the Backend servers row
(a virtual row is added if the repo has no backend), so savings are net.
- Totals in USD and INR (editable rate), per active user, per year.
- Light, Dark and Auto themes: Auto follows the system setting; a chosen theme is remembered in
the browser.
## Keeping it current
Rates were checked on the date in `assets/engine.js` (`RATES_CHECKED`). If that is more than
~90 days old when you run, or the user asks for fresh prices, check the vendors listed in
`references/pricing.md` with web search, update the numbers in `engine.js` and the date, and say
which rates changed. To support a new vendor, add a provider to `P` and its id to the category's
`o` list in `engine.js`, and a detection rule to `scripts/rules.json`.
View on GitHub