cohort-analysis — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cohort-analysis (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Builds the full SaaS cohort suite from a CRM + money source: 11 sub-tables across 3 sections (Customer Churn, MRR Churn, CAC Payback) in a single Excel workbook with green→red conditional formatting, plus per-section CSVs for SQL/raw consumption.
Ask in order. Don't skip. Don't pick defaults silently.
attio, Attio Persons or Companies, created_at is the cohort keystripe, Stripe Customers themselves (no separate CRM)csv, paste a path to a CSV with columns customer_id, email, signup_datestripe, Stripe Invoices (paid)attio, currency attribute on a CRM record (requires extra info, see Step 1b)csv, path to CSV with columns customer_id (or email), event_date, amountyes, they paste a path to a cohort,cac_amount CSV. Section 3 of the workbook will show cumulative gross profit vs CAC and flag the lifetime month each cohort breaks even.no / skip, workbook will only include the first two sections.0.8 (80%). Most SaaS companies are 70-85%.all (default, xlsx workbook + per-section CSVs)xlsx, workbook onlycsv, per-section CSVs onlysql, also dump SQL DDL+insertsevidence, also bootstrap a DuckDB+Evidence projectIf they picked Attio for money, STOP and show this verbatim before going further:
⚠️ Heads up, Attio doesn't store revenue history natively. It only holds current attribute values, so we have to reconstruct the timeline from date attributes on each customer record. To do that I need three attribute slugs:
>
1. Amount per period: the recurring amount (e.g.mrr,arr,subscription_amount,monthly_value) 2. Date paid / first invoice: when they started paying (e.g.date_paid,subscription_start,first_invoice_date) 3. Date churned: optional. When they stopped paying. Leave blank and we'll assume they're still active today.
>
Each customer becomes one event per month between date-paid and date-churned at the amount you give. This works for steady-state subscriptions but won't capture mid-cycle upgrades, downgrades, partial refunds, or one-off charges. For real revenue accuracy, point me at Stripe instead, or export your billing data to CSV.
>
What are the three Attio attribute slugs? (paste them as amount=mrr date_paid=date_paid date_churned=date_churned)Wait for them to give you the 3 slugs (or 2, if they're skipping date_churned).
| Source | Env var |
|---|---|
| Attio (CRM or money) | ATTIO_API_KEY |
| Stripe (CRM or money) | STRIPE_SECRET_KEY |
| CSV | none, just a path |
Run python skills/cohort-analysis/run.py --check-env --crm <X> --money <Y> to validate. If a key is missing, stop and tell the user to add it.
python skills/cohort-analysis/run.py \
--crm <attio|stripe|csv> \
--money <stripe|attio|csv> \
--cacs <path-to-cacs.csv> \ # optional, enables CAC payback section
--gross-margin 0.8 \ # default 0.8
--output <all|xlsx|csv|sql|evidence> \
--out-dir /tmp/cohort-<client>-<date>Optional flags:
--attio-object companies|people (default companies)--attio-amount-attr <slug> (required if --money attio)--attio-date-paid-attr <slug> (required if --money attio)--attio-date-churned-attr <slug> (optional, only if --money attio)--csv-customers <path> (only if --crm csv)--csv-revenue <path> (only if --money csv)--cohort-grain month|quarter (default month)Every run produces these metrics for every cohort × lifetime month:
Customer-side (Section 1 of the workbook, 5 sub-tables)
Revenue-side (Section 2 of the workbook, 5 sub-tables)
Unit economics (Section 3 of the workbook, only if `--cacs` given)
retained_mrr × gross_margin, accumulated)Per-cohort base stats (in `00_summary.csv` and the workbook headers)
Default output (--output all) writes to /tmp/cohort-<client>-<date>/:
cohort_table.csv, headline retained-MRR matrix (familiar shape, opens directly)00_summary.csv, one row per cohort: base counts, base MRR, CAC, profitable-since01_retained_customers.csv through 11_cac_payback_cumulative_gross_profit.csv, every sub-table as its own CSVaudit_customers.csv + audit_revenue.csv, everything that fed the join, for traceabilityShow a 4-line summary:
cohort_workbook.xlsxquick_summary output: e.g. "Jan-2026 cohort: 80 customers @ $7,851 MRR → M9: 64 customers, 81% MRR retained")/cohort-analysis or "cohort analysis for <client>"The examples/ folder ships with a richer fixture (8 cohorts, ~12 months of history, CAC values). Run end-to-end:
python skills/cohort-analysis/run.py \
--crm csv --money csv \
--csv-customers skills/cohort-analysis/examples/customers.csv \
--csv-revenue skills/cohort-analysis/examples/revenue.csv \
--cacs skills/cohort-analysis/examples/cacs.csv \
--gross-margin 0.8 \
--output all \
--out-dir /tmp/cohort-demo
open /tmp/cohort-demo/cohort_workbook.xlsxemail (lowercased) by default. Stripe customers usually carry email; Attio Persons too. For Companies → Stripe, falls back to domain match./tmp/cohort-<client>-<date>/.openpyxl. If it's not installed, the skill still produces all the CSVs; the .xlsx is skipped with a friendly message.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.