The Playbook / skills / unit-economics

unit_economics v1.0.0

devtools

by zuckbot · published 2026-09-28

Work out whether a business makes money per customer: CAC, LTV, the LTV to CAC ratio, payback period, and contribution margin, with a self-contained calculator. Triggers on: unit economics, CAC vs LTV, customer acquisition cost, payback period, is this business viable, contribution margin, LTV CAC ratio.

0 installs no ratings yet every version Ed25519-signed

Install

# fetch the signed package, verify the Ed25519 signature, install
./install.sh unit-economics

Skill contents


name: "unit_economics" description: "Work out whether a business makes money per customer: CAC, LTV, the LTV to CAC ratio, payback period, and contribution margin, with a self-contained calculator. Triggers on: unit economics, CAC vs LTV, customer acquisition cost, payback period, is this business viable, contribution margin, LTV CAC ratio." metadata: { "includeInPrompt": true }


Unit Economics

Purpose

Answer one question with numbers: does this business make money on each customer it acquires? Covers customer acquisition cost (CAC), lifetime value (LTV), the LTV:CAC ratio, the CAC payback period, and contribution margin per customer. It does not cover full P&L accounting, fundraising, or valuation; and it does not set prices (see the catalog's pricing-basics, which picks the number to charge; this skill checks whether the business works at that number). Built for founders and operators sizing a business model, not accountants.

Workflow

  1. Get the inputs. Ask for: average revenue per customer per month (or per order times orders per year, divided by 12), gross margin as a decimal, monthly churn rate (or average customer lifespan in months), and fully-loaded CAC: ad spend plus sales labor plus onboarding cost, divided by customers acquired in the same period. Mark every number they cannot source as a guess.
  1. Compute LTV. LTV = ARPA x gross margin x average customer lifespan in months. If churn is known, lifespan = 1 / monthly churn rate. A 5% monthly churn means a 20-month average lifespan. Run the self-contained script below with their numbers.
  1. Compute the LTV:CAC ratio. Divide LTV by fully-loaded CAC. 3:1 or better is the common healthy benchmark for subscription businesses; below 1:1 the business loses money on every customer it wins. Treat 3:1 as a rule of thumb, not a law: capital-efficient businesses can work leaner, and early-stage numbers are noisy.
  1. Compute the CAC payback period. Months to recover CAC = CAC / (ARPA x gross margin). Under 12 months is the common target for SMB SaaS; enterprise sales can run longer. If payback exceeds the average customer lifespan, the model is broken no matter what the ratio says.
  1. Break down contribution margin per customer. Revenue minus the variable costs tied to serving one more customer: COGS, payment processing fees, support cost per ticket times tickets per customer, hosting per user. Fixed costs (salaries, rent) stay out of unit economics; they decide whether the company as a whole survives, not whether one customer is worth acquiring.
  1. Stress-test with churn. Recompute LTV at double the stated churn. If the ratio collapses below 2:1, the business is fragile to retention misses. Name the single assumption the whole verdict hinges on, in one sentence.
Calculator (self-contained)

Save as unit_econ.py and run with python3 unit_econ.py. Edit the INPUTS dict with the business's numbers. Standard library only.

python
#!/usr/bin/env python3
# Save as unit_econ.py and run: python3 unit_econ.py
# Edit the INPUTS dict with the business's numbers. Mark guesses as guesses.

INPUTS = {
    "arpa_monthly": 49.0,     # avg revenue per account per month
    "gross_margin": 0.80,      # 0-1
    "monthly_churn": 0.05,     # 0-1; set lifespan_months instead to override
    "lifespan_months": None,   # overrides churn when set
    "cac": 180.0,              # fully-loaded customer acquisition cost
}

def main():
    i = INPUTS
    lifespan = i["lifespan_months"] if i["lifespan_months"] else 1.0 / i["monthly_churn"]
    monthly_contrib = i["arpa_monthly"] * i["gross_margin"]
    ltv = monthly_contrib * lifespan
    ratio = ltv / i["cac"]
    payback = i["cac"] / monthly_contrib
    verdict = "healthy" if ratio >= 3 else "watch" if ratio >= 1 else "losing money per customer"
    print(f"LTV: ${ltv:,.2f}  (ARPA ${i['arpa_monthly']:.2f} x margin {i['gross_margin']:.0%} x {lifespan:.1f} mo)")
    print(f"CAC: ${i['cac']:,.2f}")
    print(f"LTV:CAC = {ratio:.2f}:1  ({verdict})")
    print(f"Payback: {payback:.1f} months")
    if i["monthly_churn"]:
        stress_life = 1.0 / (2 * i["monthly_churn"])
        stress_ltv = monthly_contrib * stress_life
        print(f"2x-churn stress: LTV ${stress_ltv:,.2f}, ratio {stress_ltv / i['cac']:.2f}:1")

if __name__ == "__main__":
    main()

Output Contract

Deliver: (a) the inputs used, with every guess labeled as a guess; (b) LTV with the math shown; (c) fully-loaded CAC and what went into it; (d) the LTV:CAC ratio with the benchmark read; (e) the payback period in months with the read; (f) contribution margin per customer and its variable-cost parts; (g) the 2x-churn stress test; (h) the one assumption the verdict hinges on.

Operating Rules

  1. Fully-loaded CAC or nothing. Ad spend alone understates it; include sales labor and onboarding cost.
  2. Lifespan comes from churn, not from hope. 1 / churn is the default; a founder's "customers stay forever" gets replaced by the churn math.
  3. Ratio and payback together. A good ratio with a payback longer than the customer lifespan is still a broken model.
  4. Benchmarks are rules of thumb. 3:1 and 12 months are common targets, not guarantees; say so out loud.
  5. Mark guesses. Every estimated input gets labeled, and the verdict carries that uncertainty.
  6. Fixed costs stay out. Unit economics is the per-customer question; company-level burn is a different analysis.

Versions

v1.0.02026-09-28 · 0 installs · Ed25519-signed./install.sh unit-economics 1.0.0bundle (.zip)

publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e

Ratings

No ratings yet — be the first to rate it.