In SaaS the deal doesn't end at closed-won — that's where the revenue starts. Net revenue retention, not new logos, is the number the board watches, and it's earned in renewals and expansions long after the AE moves on. A CRM built around a one-time "value" field can't see it: it has no subscription, no ARR, no renewal date, no seat utilization. This overlay adds the recurring-revenue spine so renewal risk and expansion are queries over the same bucket.
The problem — and the money
The buyer here is the SaaS RevOps or CS leader who has to forecast renewals and expansion, not just new pipeline. A vanilla CRM shows the deal that closed; it can't answer "how much ARR is up for renewal in Q4, and which accounts are healthy enough to expand?" The payoff is a hard number the base CRM cannot produce: $120,000 of ARR due for renewal in Q4-2026, isolated from the 2027 renewals that don't belong in this quarter's forecast. That's the why — this overlay makes recurring revenue first-class so retention is measured, not guessed.
This is the CRM suite + the SaaS overlay. The seven base skills — core, lead-to-opportunity, qualification-scoring, pipeline-forecast and the rest — are unchanged. The overlay only adds a subscriptions table, revenue columns on accounts, a renewal forecast category, and two prompt tweaks. Same bucket, one copy of the rows.
What SaaS adds
A small, additive diff on top of the suite (skill: crm/saas → the
crm/overlays/saas contract):
- One table —
subscriptions(keysubscription_id: the recurring-revenue spine — one row per active contract, withmrr,seats,term_months,renewal_date,auto_renew). - Revenue columns on the
crm/coreaccountsmaster —arr,mrr,plan_tier,renewal_date,seats,seats_used,health— added withALTER TABLE … ADD COLUMNover the pg wire. A column-add on the master, never a second copy. - A forecast lane — pipeline-forecast gains
renewal+expansionstages and arenewal_commitforecast category, so weighted pipeline includes ARR expansion and renewal. - Two gate changes — lead-to-opportunity and qualification-scoring prefer product-qualified
signals (activation,
seats_used/seats, in-product usage) over marketing-qualified ones. Prompt-only; the JSON contracts are unchanged.
Apply the diff — an ALTER on accounts and the subscriptions spine:
In the crm bucket, apply the SaaS overlay: ALTER accounts ADD arr, mrr, seats, seats_used, plan_tier, renewal_date, health; create subscriptions (key subscription_id, 9 cols); seed Acme with $120,000 ARR renewing 2026-11-30 and Initech renewing in 2027.
data_pg→data_table_create→data_table_upsertAdded arr/mrr/seats/seats_used/plan_tier/renewal_date/health to accounts (ALTER over pg — the master, not a copy). Created subscriptions (merge-key subscription_id). Seeded Acme (arr 120000, renewal_date 2026-11-30) and Initech (renewal_date 2027-03-01) — so the Q4 rollup isolates Acme.
export BUCKET=crm # the SAME bucket the CRM suite built — the overlay only ADDs
# 1) revenue columns on the crm/core accounts master — ALTER over the pg wire, never a second copy
for col in "arr DOUBLE" "mrr DOUBLE" "seats INT" "seats_used INT" \
"plan_tier VARCHAR" "renewal_date VARCHAR" "health VARCHAR"; do
dodil data pg -b "$BUCKET" "ALTER TABLE accounts ADD COLUMN $col"
done
# 2) the recurring-revenue spine
dodil data table create subscriptions -b "$BUCKET" --merge-key subscription_id \
--columns-json '[{"name":"subscription_id","type":"string","nullable":false},{"name":"account_domain","type":"string"},{"name":"plan_tier","type":"string"},{"name":"seats","type":"int"},{"name":"mrr","type":"double"},{"name":"term_months","type":"int"},{"name":"start_date","type":"string"},{"name":"renewal_date","type":"string"},{"name":"auto_renew","type":"boolean"}]'
# 3) seed ARR onto accounts (partial merge) + a subscription row
dodil data table upsert accounts -b "$BUCKET" --merge --row '{"org_domain":"acme.io","arr":120000,"mrr":10000,"seats":200,"seats_used":180,"plan_tier":"enterprise","renewal_date":"2026-11-30","health":"green"}'
dodil data table upsert accounts -b "$BUCKET" --merge --row '{"org_domain":"greyparrot.ai","arr":48000,"mrr":4000,"seats":40,"seats_used":12,"plan_tier":"pro","renewal_date":"2027-03-01","health":"yellow"}'
dodil data table upsert subscriptions -b "$BUCKET" --row '{"subscription_id":"sub-acme","account_domain":"acme.io","plan_tier":"enterprise","seats":200,"mrr":10000,"term_months":12,"start_date":"2025-12-01","renewal_date":"2026-11-30","auto_renew":true}'Now the payoff read — the ARR renewal rollup that isolates the quarter:
In crm, roll up ARR due for renewal in Q4-2026 (renewal_date between 2026-10-01 and 2027-01-01), and flag accounts with low seat utilization as expansion or churn risk.
data_sqlQ4-2026 = 1 renewal due, $120,000 (Acme's Nov-30 renewal; Initech's 2027 renewal correctly excluded). Seat utilization: Acme 180/200 = 90% (expansion-ready); Greyparrot 12/40 = 30% (churn watch). The renewal forecast-category read the base CRM can't produce.
# ARR up for renewal this quarter — the renewal_commit forecast category
dodil data sql -b "$BUCKET" "
SELECT count(*) AS renewals_due, sum(arr) AS arr_up_for_renewal
FROM accounts
WHERE renewal_date >= '2026-10-01' AND renewal_date < '2027-01-01'"
# 1 | 120000 <- Acme's Nov-30 renewal; Initech's 2027 renewal excluded
# seat utilization -> expansion vs churn signal (PLG evidence the qualify gates now weight)
dodil data sql -b "$BUCKET" "
SELECT name, seats_used, seats,
round(100.0 * seats_used / seats) AS pct_used, health
FROM accounts WHERE seats IS NOT NULL ORDER BY pct_used DESC"
# Acme | 180 | 200 | 90 | green (expansion-ready)
# Greyparrot | 12 | 40 | 30 | yellow (churn watch)The two qualify gates then read seats_used/seats as a product-qualified signal: a heavily-used
account is a need the model weights, not a cold marketing lead. The gate mechanism and the four-dim
BANT JSON are unchanged from the base skill; only the prompt shifts.
Scaffold it — the one-shot
With the DODIL MCP connected, one prompt composes the suite and this overlay:
Scaffold a CRM for my SaaS company — the CRM suite plus the SaaS overlay.
Base: the full crm/core suite (accounts, contacts, leads, opportunities, activities; the
account-hierarchy graph; lead-to-opportunity + qualification-scoring + pipeline-forecast).
Then apply the SaaS overlay on the SAME bucket:
1. ALTER accounts ADD arr, mrr, seats, seats_used, plan_tier, renewal_date, health (pg wire — the
master, not a copy).
2. Create subscriptions (key subscription_id) — the recurring-revenue spine.
3. Add renewal + expansion stages to pipeline-forecast and a renewal_commit forecast category.
4. Make the two qualify gates prefer product-qualified signals (activation, seats_used/seats) over
marketing-qualified — same JSON contracts.
Seed the demo above and show the Q4 ARR renewal rollup + the seat-utilization signal.Verify
Every number below was live-validated on 2026-09-02 (org IHDIASH, throwaway bucket, torn down after):
# columns land + keyed upsert writes them
dodil data pg -b "$BUCKET" "ALTER TABLE accounts ADD COLUMN arr DOUBLE" # + mrr/seats/renewal_date/plan_tier
# subscriptions created (merge-key subscription_id, 9 cols) + upsert wal_written:true
dodil data table list -b "$BUCKET" | grep subscriptions
# the money read: Q4-2026 = 1 renewal due, $120,000 (2027 renewals excluded)
dodil data sql -b "$BUCKET" "SELECT sum(arr) FROM accounts
WHERE renewal_date >= '2026-10-01' AND renewal_date < '2027-01-01'" # 120000The ALTER-add, the subscriptions spine, and the $120,000 Q4 renewal rollup are proven live. Wiring
renewal_commit as a forecast category inside the deployed forecaster, and the PLG-preference clauses
in the two gate prompts, reuse mechanisms already proven in the base pipeline-forecast and
qualification-scoring skills.
Connect your tools
Everything the overlay wrote lives in the one DataK3 bucket, reachable by your own stack — a renewals
dashboard reads subscriptions and accounts.arr over the Postgres wire; a BI tool charts NRR
straight off the live rows. data connect crm prints the endpoints. Full, live-validated walkthrough:
Connect your tools.
Composes
This page is not a fork of the CRM — it is a composition:
- Base: the seven CRM suite skills (
crm/core,crm/lead-to-opportunity,crm/qualification-scoring,crm/pipeline-forecast, …) — the system of record, unchanged. - Overlay:
crm/overlays/saas— the additive diff above (the subscriptions spine, the ARR/seat columns, the renewal forecast lane, the PLG-preferring qualify gates).
Read the base to learn the mechanics; this overlay is the small, industry-specific diff on top.