Arr waterfall
@ledgerly/arr-waterfall
Turn a monthly subscriptions export into an ARR waterfall: starting ARR, new, reactivation, expansion, contraction, churn, ending ARR, plus NRR and GRR. Writes markdown, CSV, and a per-customer movements file. Works offline from a CSV.
- Activity
- New: be the first to try it
- Installs
- 0 installs
- Likes
- 0 likes
- Clones
- 0 clones
- 1{
- 2 "name": "arr-waterfall",
- 3 "owner": "ledgerly",
- 4 "version": "1.0.0",
- 5 "type": "skill",
- 6 "description": "Turn a monthly subscriptions export into an ARR waterfall: starting ARR, new, reactivation, expansion, contraction, churn, ending ARR, plus NRR and GRR. Writes markdown, CSV, and a per-customer movements file. Works offline from a CSV.",
- 7 "category": "finance",
- 8 "license": "MIT",
- 9 "compat": ["claude-code"],
- 10 "permissions": {
- 11 "shell": ["node scripts/arr-waterfall.mjs"],
- 12 "files": { "read": ["./data/**"], "write": ["./out/arr-waterfall*"] }
- 13 },
- 14 "tests": {
- 15 "cases": [
- 16 {
- 17 "name": "builds the waterfall and cohort NRR from the example export",
- 18 "inputs": {},
- 19 "checks": [
- 20 { "type": "command_exits_zero", "command": "node scripts/arr-waterfall.mjs examples/subscriptions.csv --out out/arr-waterfall" },
- 21 { "type": "file_exists", "path": "out/arr-waterfall.csv" },
- 22 { "type": "file_contains", "path": "out/arr-waterfall.md", "text": "Ending ARR $183,600" },
- 23 {
- 24 "type": "output_matches_schema",
- 25 "path": "out/arr-waterfall.json",
- 26 "schema": {
- 27 "type": "object",
- 28 "required": ["totals", "period_cohort", "months", "unreconciled_months"],
- 29 "properties": {
- 30 "totals": {
- 31 "type": "object",
- 32 "properties": {
- 33 "starting_arr": { "const": 153600 },
- 34 "new": { "const": 51600 },
- 35 "reactivation": { "const": 8400 },
- 36 "expansion": { "const": 14400 },
- 37 "contraction": { "const": 8400 },
- 38 "churn": { "const": 36000 },
- 39 "ending_arr": { "const": 183600 }
- 40 }
- 41 },
- 42 "period_cohort": {
- 43 "type": "object",
- 44 "properties": { "nrr": { "const": 0.8438 }, "grr": { "const": 0.75 } }
- 45 },
- 46 "months": { "type": "array", "minItems": 5, "maxItems": 5 },
- 47 "unreconciled_months": { "type": "array", "maxItems": 0 }
- 48 }
- 49 }
- 50 }
- 51 ]
- 52 },
- 53 {
- 54 "name": "accepts an arr column and sums duplicate rows",
- 55 "inputs": {
- 56 "data/subs.csv": "month,customer_id,arr\n2026-01,a,12000\n2026-01,a,6000\n2026-01,b,10000\n2026-02,a,24000\n2026-02,c,5000\n"
- 57 },
- 58 "checks": [
- 59 { "type": "command_exits_zero", "command": "node scripts/arr-waterfall.mjs data/subs.csv --out out/arr-waterfall" },
- 60 {
- 61 "type": "output_matches_schema",
- 62 "path": "out/arr-waterfall.json",
- 63 "schema": {
- 64 "type": "object",
- 65 "properties": {
- 66 "totals": {
- 67 "type": "object",
- 68 "properties": {
- 69 "starting_arr": { "const": 28000 },
- 70 "new": { "const": 5000 },
- 71 "expansion": { "const": 6000 },
- 72 "churn": { "const": 10000 },
- 73 "ending_arr": { "const": 29000 }
- 74 }
- 75 }
- 76 }
- 77 }
- 78 }
- 79 ]
- 80 }
- 81 ]
- 82 }
- 83}
