Turns your Stripe data (exports or a read-only key) and bank exports into reconciled SaaS metrics, a driver-based .xlsx model with live formulas, runway scenarios and a board update, where every number ties back to source rows.
Ten skills that do a fractional CFO's setup month as scripts against your own exports, each ending in a machine-checked gate that prints PASS, FAIL or BLOCKED with the file, row and value behind every finding. Sort the exports by their headers (or pull Stripe read-only with a restricted key) and write the finance contract (price mapping found in your invoice lines, MRR policy, FX rates, bank accounts with statement balances, categorization rules, contracts invoiced outside Stripe, payroll split); normalize Stripe invoices, line items, subscriptions, balance transactions and payouts, with annual plans, discounts, prorations, trials, refunds and multi-currency handled and every invoice reconciled to its lines to the cent, every charge tied to an exported invoice and FX checked against what Stripe settled; prove each bank account's running balance against the statement, categorize every row, net out transfers between your own accounts and match every Stripe payout to a deposit; build the MRR waterfall, NRR and GRR and cohort tables, tied to the subscriptions export; compute CAC, CAC payback, gross margin, LTV and burn multiple with every input cited to bank rows, with one-off inflows and owner money kept out of burn; write a real .xlsx driver model with live formulas, then verify the workbook as you edited and saved it in Numbers or LibreOffice (no typed-over formulas, no #REF!, every formula recomputed, every driver labelled seed, plan or edit); project base, downside and upside runway and the smallest spending cut that reaches your target runway; and write the board update, where every number carries its source, is bound to the metric its sentence names, and nothing is written while a gate is failing or stale. Python 3 standard library only, no network calls except the optional read-only Stripe pull; LibreOffice optional. Management metrics, not accounting or GAAP revenue recognition. Requires an AI that can run commands on your computer (Claude Code, Codex or Cursor). The worked example is a fictional SaaS company; every skill reads your own contract first.
Quorvel is not a real company. A route-planning SaaS for small delivery fleets: monthly, quarterly and annual plans in USD and EUR billed through Stripe, one enterprise fleet invoiced by wire, two bank accounts. Quorvel's Stripe and bank exports are generated for 18 months with 17 planted data, accounting, workbook and narrative traps, plus a fixed twin. The whole chain ran on both from the scripts exactly as the skills ship them, and the fixed twin's metrics were compared with ground truth computed by separate code from the generator's own records.
Month-end close as first exported: Every planted trap raised; the board update refused to write
| Gate | Skill | Status | Blocker | Major | Minor |
|---|---|---|---|---|---|
| contract | finance-contract | PASS | 0 | 0 | 0 |
| stripe | stripe-revenue-ingest | FAIL | 3 | 7 | 1 |
| bank | bank-cash-ingest | FAIL | 2 | 6 | 0 |
| mrr | mrr-movements | FAIL | 0 | 3 | 0 |
| unit-economics | saas-unit-economics | FAIL | 0 | 3 | 0 |
| model | model-integrity-check | FAIL | 2 | 8 | 1 |
| runway | runway-scenarios | FAIL | 1 | 3 | 0 |
| update | investor-board-update | FAIL | 6 | 1 | 0 |
Fixed twin: Every gate PASS, the update written, and every metric equal to the ground truth to the cent
From the report
STRIPE-INTERVAL-MISMATCH · price_team_y
Contract says interval_months 1 but 21 lines bill 12-month periods: trusting the contract would book each annual invoice as 12x its monthly value.
Fix: Set prices.price_team_y.interval_months to 12.
BANK-REVENUE-OUTSIDE-STRIPE · checking, row 160
9 receipts (22,500.00) are categorized as revenue but are not Stripe payouts and match no offline contract: an enterprise fleet paying by wire would be missing from MRR.
Fix: Declare the contract in offline_contracts.
BANK-TRANSFER-UNMATCHED · savings, row 11
A 60,000.00 sweep to checking has no opposite transfer; the receiving row (ONLINE DEPOSIT REF 88213) is categorized as other income, so the same money would count twice.
Fix: Add a rule so both legs are categorized as a transfer.
MODEL-HARDCODED-CELL · Model!H9
Model!H9 should be =H4*Inputs!$B$9 but holds the typed value 1234.56: it no longer moves with the drivers.
Fix: Restore the formula; change drivers on the Inputs sheet instead.
RUNWAY-CASH-START-MISMATCH · Inputs!B3
Starting cash on Inputs is 900,000.00; the reconciled bank closing cash is 729,327.86, so every runway number would be off.
Fix: Set Inputs!B3 to the bank closing balance.
The exports are generated in Stripe's column layouts by the fixture, not downloaded from a Stripe account.
The ground truth shares the pack's definitions: the run proves the arithmetic and reconciliation, not that the definitions are the right ones for your board.
The workbook was recalculated by LibreOffice 26.2 and re-saved by Numbers; it was not opened in Microsoft Excel.
Optional
Questions or a problem with 1.3.1? Email support@skillme.dev.
Arranged in the author's recommended order. Walk through them in sequence, or open any one on its own.
Starts a founder finance close from Stripe and bank CSV exports – installs the pack's shared scripts, sorts every export file by its exact headers (Stripe invoices, invoice line items, subscriptions, itemized balance transactions, payouts, an FX rates file.
Completes and validates the finance-contract.json every step of a founder finance close obeys – company, base currency, period, Stripe price mapping (kind and interval), MRR policy, per-file amount units, FX rates source.
Reads Stripe CSV exports (invoices, invoice line items, subscriptions, itemized balance transactions, payouts), or pulls the same data read-only with a restricted API key, and normalizes every invoice line to monthly recurring value in the base currency.
Reads bank statement CSVs (any bank: columns mapped in the contract, comma or semicolon, UTF-8 or Windows-1252, oldest-first or newest-first, single amount or debit/credit, CR/DR and currency-symbol amounts, failed and pending rows dropped by status).
Builds month-end MRR per customer from the normalized Stripe lines plus declared offline contracts and turns it into the monthly MRR waterfall (new, expansion, contraction, churn, reactivation, FX), ARR, customer counts, logo churn.
Computes CAC, ARPA of new customers, gross margin, CAC payback in months on gross-margin-adjusted new MRR, and burn multiple over a trailing window from the reconciled bank categories, the owner's payroll split and the MRR waterfall.
Writes a driver-based operating model as a real .xlsx workbook with live formulas, using only the Python standard library – an Inputs sheet seeded from the reconciled gates with the source of every seed (new customers and their growth for a stated number of…
Re-opens the driver-model workbook as the founder left it (edited and saved in Excel, Numbers or LibreOffice) and proves it – every Model and Checks cell still a formula after normalizing what spreadsheets rewrite on save (quoted sheet names, $ anchors.
Projects base, downside and upside cash scenarios from the model workbook's drivers (so the founder's edits count, labelled as edits) and reports months of runway, the zero-cash month, the break-even month (and whether it comes only after cash runs out).
Writes the monthly board or investor update (Markdown and a self-contained HTML page) from the finance gates – key numbers (MRR and the part outside Stripe, ARR, growth, customers, churn, NRR, GRR, recognized revenue, cash collected, gross and net burn.