--- name: ops-revenue description: "OPS on-demand: This skill should be used when the user asks to \"burn rate\", \"runway\", or…" argument-hint: '[costs|revenue|credits|runway|all]' allowed-tools: - Bash - Read - Grep - Glob - Skill - AskUserQuestion - WebFetch - Write effort: low maxTurns: 20 disallowedTools: - Edit - NotebookEdit --- # OPS ► REVENUE & COSTS Load `ops-rules` before acting. Public repo (no personal data). Outbound: one draft → one approval → one send. If `AskUserQuestion` / `Workflow` are missing, follow Rule 10 in `ops-rules` (Hermes: numbered options / two-turn Telegram card; `delegate_task`). ## Runtime Context Before executing, load available context: 1. **Preferences**: Read `${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json` - `timezone` — display all timestamps correctly 2. **Daemon health**: Read `${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json` - If `action_needed` is not null → surface it before the cost report 3. **Secrets**: AWS Cost Explorer requires credentials. ### Secret Resolution - AWS: check `$AWS_PROFILE` / `$AWS_ACCESS_KEY_ID` → `doppler secrets get AWS_ACCESS_KEY_ID --plain` → vault query cmd from prefs - If no credentials available, report "AWS costs unavailable — credentials not configured" and show only the revenue pipeline from registry ## CLI/API Reference ### AWS burn doctrine (CRITICAL — 2026-07-22) **Never report plain `UnblendedCost` / `NetUnblendedCost` totals as "spend".** Startup credits, SPP discounts, and Savings Plan negation make those nets ≈ $0 while real Usage burn is hundreds/day. **Always** use `RECORD_TYPE=Usage` for burn, pace, spikes, runway, and Bedrock. Show credits only as a mask line. Canonical helper (prefer this over raw `aws ce`): ```! ${CLAUDE_PLUGIN_ROOT}/scripts/aws-usage-cost.sh snapshot 2>/dev/null || echo '{}' ``` ```! ${CLAUDE_PLUGIN_ROOT}/scripts/aws-usage-cost.sh all 2>/dev/null || true ``` | Command | Usage | Output | | ------- | ----- | ------ | | `scripts/aws-usage-cost.sh snapshot` | MTD/prev Usage burn + 7d daily + top services + credit mask | JSON | | `scripts/aws-usage-cost.sh daily 7` | Last N days Usage totals | JSON array | | `scripts/aws-usage-cost.sh by-service mtd` | MTD Usage by service | JSON array | | `scripts/aws-usage-cost.sh record-types` | Credit / Usage / SP breakdown (mask only) | JSON array | | `aws ce get-cost-and-usage … --filter '{"Dimensions":{"Key":"RECORD_TYPE","Values":["Usage"]}}'` | Raw Usage-only CE (fallback if helper missing) | Cost JSON | | `aws ce list-savings-plans-purchase-recommendation` | Savings plan recommendations | JSON | --- ## Phase 1 — Gather financial data in parallel ### FinOps dashboard — canonical revenue + burn If `FINOPS_DASHBOARD_URL` and `FINOPS_OPS_API_TOKEN` are configured, the dashboard is the single source of truth for per-project MRR, 30d revenue, and current burn. Per-DBA breakdown comes from the Stripe revenue snapshots ingested via `/api/ops/revenue`. Falls open to `{}` if unset — the per-source AWS / RevenueCat queries below run as fallback. **If the dashboard `current_month_spend` is ≈ $0 while Usage burn from `aws-usage-cost.sh` is material, trust the helper** (dashboard may still be credit-masked or ingest-empty). Always dual-check with the Usage helper. ```! ${CLAUDE_PLUGIN_ROOT}/scripts/finops-bridge.sh snapshot 2>/dev/null || echo "{}" ``` ```! ${CLAUDE_PLUGIN_ROOT}/scripts/finops-bridge.sh revenue project 2>/dev/null || echo "{}" ``` When the dashboard returns data, render the per-project MRR section from `groups[]` rather than from RevenueCat-only data. ### AWS costs — Usage burn (authoritative) ```! ${CLAUDE_PLUGIN_ROOT}/scripts/aws-usage-cost.sh snapshot 2>/dev/null || echo '{}' ``` Fallback if helper missing: ```bash USAGE_FILTER='{"Dimensions":{"Key":"RECORD_TYPE","Values":["Usage"]}}' aws ce get-cost-and-usage \ --time-period "Start=$(date +%Y-%m-01),End=$(date +%Y-%m-%d)" \ --granularity MONTHLY \ --metrics "UnblendedCost" \ --filter "$USAGE_FILTER" \ --group-by "Type=DIMENSION,Key=SERVICE" \ --output json 2>/dev/null ``` ### AWS costs (last 3 months Usage trend) ```bash USAGE_FILTER='{"Dimensions":{"Key":"RECORD_TYPE","Values":["Usage"]}}' aws ce get-cost-and-usage \ --time-period "Start=$(date -v-3m +%Y-%m-01 2>/dev/null || date -d '3 months ago' +%Y-%m-01),End=$(date +%Y-%m-%d)" \ --granularity MONTHLY \ --metrics "UnblendedCost" \ --filter "$USAGE_FILTER" \ --output json 2>/dev/null ``` ### AWS credits / discount mask (not spend) ```! ${CLAUDE_PLUGIN_ROOT}/scripts/aws-usage-cost.sh record-types 2>/dev/null || echo '[]' ``` ```bash aws ce list-savings-plans-purchase-recommendation --output json 2>/dev/null || echo '{}' aws ce get-credits --output json 2>/dev/null || echo "credits API unavailable" ``` ### AWS cost forecast (end of month) Note: CE forecasts are often net-of-credits. Prefer `eom_pace` from `aws-usage-cost.sh snapshot` (7d Usage avg × days in month) as the burn forecast. ```bash aws ce get-cost-forecast \ --time-period "Start=$(date +%Y-%m-%d),End=$(date +%Y-%m-28)" \ --metric "UNBLENDED_COST" \ --granularity MONTHLY \ --output json 2>/dev/null ``` ### Project registry (revenue stage) ```bash cat "${CLAUDE_PLUGIN_ROOT}/scripts/registry.json" 2>/dev/null | jq '[.projects[] | {alias, name, stage: (.revenue_stage // .revenue.stage // "pre-revenue"), mrr: (.mrr // 0), source: (.source // "git"), type: (.type // "repo")}]' ``` ### External project revenue (Shopify, custom SaaS) ```! ${CLAUDE_PLUGIN_ROOT}/bin/ops-external 2>/dev/null || echo '[]' ``` For Shopify projects showing `status: "healthy"`, pull GMV via Shopify Admin API: ```bash # For each Shopify project in registry with valid credentials: STORE_URL="[from project.shopify.store_url]" TOKEN="[from env var named in project.shopify.credential_key]" curl -s -H "X-Shopify-Access-Token: $TOKEN" \ "https://$STORE_URL/admin/api/2024-10/orders.json?status=any&created_at_min=$(date -v-30d +%Y-%m-%dT00:00:00Z 2>/dev/null)&limit=250" 2>/dev/null ``` Include Shopify GMV in the revenue pipeline table with source=shopify. --- ## Phase 2 — Render dashboard ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ OPS ► REVENUE & COSTS — [month] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ AWS USAGE BURN (RECORD_TYPE=Usage — not credit-masked net) This month usage: $[X] ← from aws-usage-cost.sh mtd_usage Forecast (EOM pace): $[X] ← eom_pace (7d Usage avg × days) Last month usage: $[X] MoM change: [+/-X%] 7d avg/day: $[X] Top services (Usage): [service] $[X] ([%] of usage) [service] $[X] ... CREDITS / MASK (do not report as low spend) Credits applied MTD: $[X] (record_types Credit) Discounts MTD: $[X] Net after mask: ~$0 is EXPECTED when credits cover burn Credits remaining: $[X] (if API available) Expires: [date] Months cover at pace: [N] REVENUE PIPELINE PROJECT SOURCE STAGE MRR/GMV STATUS ────────────────────────────────────────────────────────────── [project] git [stage] $[X] [status] [project] shopify [stage] $[X] GMV [status] [project] custom [stage] $[X] [status] ... ────────────────────────────────────────────────────────────── TOTAL MRR $[X] TOTAL SHOPIFY GMV (30d) $[X] RUNWAY ESTIMATE Monthly burn (AWS): $[X] Total MRR: $[X] Net burn: $[X/month] Credits cover: [N months] Cash runway: [depends on external data] ────────────────────────────────────────────────────── ``` Use **batched AskUserQuestion calls** (max 4 options each): AskUserQuestion call 1: ``` [Drill into AWS costs by service] [Show cost anomalies (spike detection)] [Export cost report] [More...] ``` AskUserQuestion call 2 (only if "More..."): ``` [Update project revenue stage] [Set budget alert] ``` --- ## Route by `$ARGUMENTS` | Argument | Action | | -------- | ---------------------------- | | costs | Show only AWS cost breakdown | | credits | Show only credits and expiry | | revenue | Show only revenue pipeline | | runway | Calculate and show runway | | (empty) | Show full dashboard | Use AskUserQuestion after the dashboard for next action. --- ## Native tool usage ### WebFetch — billing API fallback When `aws ce` commands fail or return incomplete data, use `WebFetch` to query the AWS Cost Explorer API directly. Also useful for fetching Stripe/billing provider data if configured. ### Write — export reports When user selects "Export cost report" (option c), use `Write` to save the report as a dated file: ``` Write(file_path: "/tmp/ops-revenue-[date].md", content: "[formatted report]") ```