skills-ws
Version:
87 agent skills for AI coding assistants — marketing, growth, web3, dev, design & operations. Built for OpenClaw, Claude Code, Cursor, and Codex.
353 lines (297 loc) • 23 kB
Markdown
---
name: revenue-operations
description: "RevOps for B2B SaaS — segmented funnel benchmarks, forecasting rigor, capacity-based quota/territory planning, GTM alignment, dashboard SQL, and a 2026 tooling stack. Use when defining funnel stages, building a forecast or quota model, auditing the GTM tech stack, or instrumenting pipeline/retention dashboards."
---
# Revenue Operations
## Workflow
### 1. Revenue Funnel Definitions
Align ALL teams on the same definitions:
| Stage | Definition | Owner | SLA |
|-------|-----------|-------|-----|
| Visitor | Hit website or content | Marketing | — |
| Lead | Known contact (form fill, signup) | Marketing | Enrich within 24h |
| MQL | Meets scoring threshold (fit + engagement) | Marketing | Route within 5 min |
| SAL | Sales accepted, meeting booked | SDR/BDR | Contact within 1 hour |
| SQL | Qualified by sales (BANT/MEDDIC confirmed) | AE | Discovery within 3 days |
| Opportunity | In pipeline with defined next steps | AE | Advance or close within 90 days |
| Closed Won | Contract signed, revenue booked | AE → CS | Handoff within 48h |
**Conversion benchmarks — segment before you compare.** Public "B2B SaaS averages" are nearly useless because conversion is dominated by motion (PLG vs sales-led), ACV, channel (inbound vs outbound), ICP fit, and market maturity. Treat the table below as *order-of-magnitude priors*, not targets — then compute your own baselines (next).
| Stage transition | PLG / self-serve (low ACV <$5k) | Inbound sales-led (mid ACV $5k–50k) | Outbound / enterprise (ACV >$50k) |
|-----------------|-------------------------------|------------------------------------|-----------------------------------|
| Visitor → Lead (signup) | 2–8% | 1–3% | <1% (ABM, not volume) |
| Lead → MQL | n/a (PQL instead) | 15–35% | 25–45% (tight ICP) |
| MQL/PQL → SAL (accepted) | 5–15% PQL→sales | 50–70% | 60–85% |
| SAL → SQL | 50–70% | 40–60% | 35–55% (longer qual) |
| SQL → Opportunity | 60–80% | 50–70% | 45–65% |
| Opportunity → Closed Won | 25–40% | 18–30% | 15–25% (more stakeholders) |
| Blended visitor→won | varies widely | 0.3–1.5% | <0.3% |
Outbound-sourced opps usually convert at a *higher* win rate but *lower* top-of-funnel volume than inbound; PLG replaces MQL with **PQL** (product-qualified lead — hit an activation/usage threshold) and SAL with a sales-assist trigger.
**Calculate your own baseline (do this before setting any target):**
```sql
-- 90-day trailing stage-to-stage conversion, segmented by motion + source
-- (assumes an opportunities table with stage-entry timestamps and a deals/leads source)
WITH cohort AS (
SELECT
o.opportunity_id,
o.acv_band, -- '<5k' | '5-50k' | '>50k'
o.source_channel, -- 'plg' | 'inbound' | 'outbound'
MAX(CASE WHEN h.stage = 'SQL' THEN 1 ELSE 0 END) AS reached_sql,
MAX(CASE WHEN h.stage = 'Opportunity' THEN 1 ELSE 0 END) AS reached_opp,
MAX(CASE WHEN h.stage = 'Closed Won' THEN 1 ELSE 0 END) AS reached_won
FROM opportunities o
JOIN stage_history h USING (opportunity_id)
WHERE o.created_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2, 3
)
SELECT
acv_band, source_channel,
COUNT(*) AS opps,
ROUND(100.0 * SUM(reached_opp) / NULLIF(SUM(reached_sql), 0), 1) AS sql_to_opp_pct,
ROUND(100.0 * SUM(reached_won) / NULLIF(SUM(reached_opp), 0), 1) AS opp_to_won_pct
FROM cohort
GROUP BY 1, 2
ORDER BY 1, 2;
```
Recompute quarterly, watch the *trend* (your own series) over the absolute number, and segment any rate you report by ACV band + source. A single blended funnel rate hides the segments that actually need fixing.
### 2. Forecasting Models
**Weighted pipeline (standard):**
```
Deal forecast = Deal value × Stage probability
Total forecast = Σ all deal forecasts
```
**Historical conversion (more accurate):**
```
Expected revenue = Current stage count × Historical stage-to-close rate × Average deal size
```
**Bottoms-up / category roll-up (most accurate, most work):**
```
Rep forecast = Commit + (Best case × historical best-case close rate) + (Pipeline × historical pipeline-create-to-close rate)
Team forecast = Σ rep forecasts × per-rep calibration multiplier (see below)
```
Use *your own* historical close rates per category, not 0.5 / 0.15 magic numbers — derive them from the last 2–4 quarters by rep and segment.
**Define forecast categories explicitly** (the #1 cause of bad forecasts is undefined categories, not bad reps):
| Category | Definition — every condition must hold | Typical close rate |
|----------|----------------------------------------|--------------------|
| Commit | Verbal/written yes, paper in motion, close date this period, owner would bet their number on it | 85–95% |
| Best case | Real upside; could close this period if 1–2 specific risks clear; named next step on calendar | 30–60% |
| Pipeline | Qualified, active, but not expected to close this period | = stage/historical rate |
| Omitted | Stalled, no next step, or close date already pushed twice | exclude from forecast |
**Forecast hygiene signals to inspect weekly (per deal):**
- **Close-date push rate** — count of times close date moved out. ≥2 pushes ⇒ deal is at risk regardless of category.
- **Stage aging** — days in current stage vs your segment median. Flag deals >1.5× median (going stale).
- **Next-step quality** — is there a *scheduled, mutual* next step (meeting/MAP milestone), not "follow up"? No next step ⇒ not a commit.
- **Coverage gap** — Commit + weighted pipeline vs target; if short, the fix is *new pipeline this period*, not pressure on existing deals.
```sql
-- Deals that should be challenged: pushed twice OR stale OR no next step
SELECT opportunity_id, owner, amount, stage, close_date, push_count,
date_part('day', now() - stage_entered_at) AS days_in_stage,
next_step_at
FROM opportunities
WHERE forecast_category IN ('commit','best_case')
AND ( push_count >= 2
OR date_part('day', now() - stage_entered_at) >
1.5 * (SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY days_in_stage)
FROM stage_durations s WHERE s.stage = opportunities.stage)
OR next_step_at IS NULL )
ORDER BY amount DESC;
```
**Forecast accuracy tracking:**
| Month | Forecast | Actual | Accuracy | Bias |
|-------|----------|--------|----------|------|
| Jan | $250k | $230k | 92% | +8% (over) |
| Feb | $280k | $310k | 90% | −11% (under) |
| Mar | $300k | $275k | 92% | +9% (over) |
Track both **accuracy** (|forecast − actual| / actual) and **bias** (signed, to catch consistent over/under-calling). Target ±10% accuracy *and* near-zero average bias. A persistent miss is a *diagnosis to run*, not a verdict on reps — check, in order:
1. **Stage/category definitions** — are "commit" and "best case" applied consistently across reps?
2. **CRM hygiene** — stale close dates, missing next steps, amounts not updated.
3. **Slippage / push rate** — are deals real but landing a period late? (fix close-date discipline, not the number).
4. **Pipeline creation** — was enough new pipeline created early enough to hit coverage?
5. **Seasonality / deal-desk & legal / procurement delays** — late-stage drag outside the rep's control.
6. **Product or pricing changes, churn/expansion timing** — shifts that move close dates.
7. **Rep calibration** — *only after the above*: some reps are reliably optimistic, others sandbag. Build a per-rep calibration multiplier from their trailing 4-quarter forecast-vs-actual, coach with the data, and apply the multiplier in the roll-up rather than assuming intent.
### 3. GTM Alignment
**Weekly GTM standup (30 min):**
- Marketing: pipeline contribution this week, upcoming campaigns
- Sales: deal updates, blockers, competitive intel
- CS: churn risks, expansion opportunities, product feedback
- RevOps: funnel health, forecast update, process issues
**Monthly revenue review (60 min):**
- Funnel conversion rates vs targets
- Pipeline coverage (3x target = healthy)
- Win rate trends by segment, source, rep
- Churn and expansion ARR
- Forecast vs actual analysis
### 4. Quota & Territory Planning
**Capacity model (build this bottoms-up — `Company target / #AEs × 1.15` is too naive: it ignores ramp state, attainment distribution, attrition, overlays, and the new-logo vs expansion split).** Plan capacity and quota separately, then reconcile.
Order of operations:
1. **Split the number.** Board target → new-logo bookings + expansion bookings (NRR-driven, often owned by CS/AM, not AEs). Only assign the *new-logo* portion (plus any AE-owned expansion) to AE quota.
2. **Quota per ramped AE** is set so that *expected attainment*, not full quota, covers the target. If reps historically attain ~70% on average, gross-up the quota: `quota = (target per head) / expected_attainment`. Carry quota above the number on purpose (typical aggregate over-assignment 15–25%) so that median attainment still hits plan.
3. **Convert headcount to ramped-equivalents** using the ramp curve, not a raw count — a rep in month 3 is ~0.25 of a ramped AE.
4. **Discount for attrition** over the period (ramped capacity lost mid-year is rarely backfilled in time).
5. **Apply seasonality** — distribute quota by historical bookings-by-month, not 1/12 per month.
6. **Check coverage** — pipeline needed = quota / weighted win rate; if marketing+outbound can't create it, the quota is fiction.
```text
# Worked example — capacity in "ramped-AE equivalents"
new_logo_target = $12.0M # AE-owned slice of the board number
expected_attainment = 0.72 # trailing median, NOT 100%
attrition_haircut = 0.90 # ~10% ramped capacity lost in-year
ramp_curve (% of full quota by tenure month) = {1-2:0, 3:0.25, 4:0.50, 5:0.75, 6+:1.0}
# Sum ramped-equivalents across the roster (each AE weighted by their month in-period):
ramped_equiv = Σ ramp_curve[ae.tenure_month] # e.g. 9 fully-ramped + 4 ramping = 10.0 equiv
effective_capacity_heads = ramped_equiv × attrition_haircut # 10.0 × 0.90 = 9.0
# Quota grossed-up for expected attainment, then over-assigned for safety:
quota_per_ramped_AE = (new_logo_target / effective_capacity_heads) / expected_attainment
= ($12.0M / 9.0) / 0.72 ≈ $1.85M
aggregate_quota = quota_per_ramped_AE × ramped_equiv ≈ $18.5M # ~1.5× the $12M target
expected_bookings = aggregate_quota × expected_attainment ≈ $13.3M # cushion above $12M target
```
| Capacity input | Source | Why it matters |
|----------------|--------|----------------|
| Expected attainment | Trailing 4–6 quarters, by segment | Setting quota = target/heads assumes 100% attainment (never happens) |
| Ramp curve | Time-to-first-deal + time-to-full-productivity cohorts | New hires are fractional capacity for ~2 quarters |
| Attrition / backfill lag | HR + recruiting time-to-fill | Mid-year departures shrink delivered capacity |
| Sales cycle | Avg days SQL→won by segment | Late-period hires can't contribute bookings this period |
| Territory TAM | Accounts × ICP fit × whitespace | Quota must track territory potential, not be flat |
| Manager/overlay credit | Comp plan | Don't double-count overlay or manager-sourced deals in AE quota |
| Expansion vs new-logo | NRR model | Expansion is usually a separate motion/owner; don't load it onto new-logo AEs |
**Territory design principles:**
- **Balance by potential, not count** — score each territory's TAM (target accounts × ICP fit × whitespace/expansion headroom) and aim for similar *expected pipeline*, not equal account counts.
- **Account for existing relationships** — don't reassign active opportunities; carve around in-flight deals.
- **Minimize disruption from churn** — keep at-risk renewals with the owning rep/CSM through the renewal.
- **Geographic/segment clustering** only where it reduces real friction (timezone, language, field travel); for inside sales, cluster by vertical or persona instead.
- **Review quarterly** — territories drift as markets, headcount, and product change; rebalance with the TAM score, not gut feel.
**Ramp schedule:**
| Month | % of full quota | Expectation |
|-------|----------------|-------------|
| 1-2 | 0% | Training, shadowing, certification |
| 3 | 25% | First qualified meetings |
| 4 | 50% | First deals in pipeline |
| 5 | 75% | First closed deals |
| 6+ | 100% | Fully ramped |
### 5. Handoff Processes
**Marketing → SDR (MQL handoff):**
```
Trigger: Lead score ≥ MQL threshold
Data passed: Lead source, content consumed, pages visited, company info, score breakdown
SDR action: Research (5 min) → personalized outreach within 1 hour
Feedback loop: SDR marks SAL accepted/rejected with reason → Marketing adjusts scoring
```
**SDR → AE (SAL handoff):**
```
Trigger: Discovery call completed, BANT confirmed
Data passed: Pain points, budget range, timeline, decision process, competitors
AE action: Review notes → demo prep → schedule demo within 3 days
Handoff format: Warm intro email (SDR introduces AE + summarizes conversation)
```
**AE → CS (Closed Won handoff):**
```
Trigger: Contract signed
Data passed: Contract terms, use case, success criteria, stakeholders, technical requirements
CS action: Onboarding kickoff within 48 hours
Handoff format: Internal doc + joint call (AE + CS + customer)
```
### 6. Tech Stack Audit
**Core RevOps stack (mid-2026 naming — verify current product names/pricing at each vendor's site before standardizing):**
| Layer | Tools (2026) | Purpose / notes |
|-------|------|---------|
| CRM | Salesforce, HubSpot | System of record. Salesforce for complex/enterprise process; HubSpot for speed + bundled marketing/ops. |
| Engagement / sequencing | Salesloft, Outreach, HubSpot Sales | Multi-touch cadences, dialer, task automation. |
| Conversation intelligence | Gong, **ZoomInfo Chorus** (formerly standalone Chorus.ai), Salesloft/Clari Copilot | Call recording, AI call summaries, deal/risk signals, auto-CRM-logging. Use the AI summaries to enforce next-step + MEDDIC field hygiene. |
| Enrichment | **HubSpot Breeze Intelligence** (the former Clearbit — acquired by HubSpot 2023, rebranded 2024; standalone Clearbit API is wound down), ZoomInfo, Apollo, **Clay** (waterfall enrichment across many providers) | Contact/company/firmographic + intent data. Budget for **per-credit cost**: enrichment and intent are usage-priced, so meter credit burn per enriched record and cap auto-enrichment to ICP-fit leads. |
| Account/PLG signals | Common Room, June, Pocus, HubSpot/SFDC product-usage objects | Capture **product-led sales (PLS)** signals — activation, usage thresholds, multiple users on one domain — and surface PQAs (product-qualified accounts) to sales. |
| Routing / scheduling | **LeanData, Chili Piper, Default, RevenueHero** | Lead-to-account matching, round-robin/territory assignment, instant inbound meeting booking. This is what actually delivers your <5-min speed-to-lead SLA. |
| Reverse ETL / warehouse-native | **Hightouch, Census** (sync from Snowflake/BigQuery/Databricks → CRM & tools) | Warehouse-native GTM: model lead scores, PQLs, health, and attribution in the warehouse (dbt) as the source of truth, then sync to operational tools. Increasingly the backbone for scaling RevOps. |
| Attribution | HubSpot, Dreamdata, HockeyStack, warehouse + dbt models | Multi-touch attribution; prefer warehouse-modeled attribution once volume justifies it. |
| BI / dashboards | Looker, Metabase, Omni, Hex | Cross-functional reporting on one governed dataset. |
| Forecasting / RevOps platform | Clari, BoostUp, Gong Forecast | Roll-up forecasting, pipeline inspection, scenario/coverage analysis. |
| Communication | Slack/Teams + CRM integration | Deal alerts, routing notifications, forecast nudges. |
**AI/data hygiene & privacy (2026):**
- **AI-assisted CRM hygiene** — conversation-intelligence and CRM-AI features (Gong, Breeze, Einstein, Clari) auto-fill next steps, contact roles, and competitor mentions from calls/emails. Treat them as *assistive*: spot-check accuracy and keep a human owner for stage/forecast-category changes.
- **Privacy/consent** — enrichment and intent data are subject to GDPR/CCPA and the EU AI Act. Keep a lawful basis + suppression list for enriched contacts, honor opt-outs across all tools, and don't sync sensitive personal data into systems that don't need it.
**Audit checklist:**
- [ ] One clear system of record per object (account, contact, opportunity); no duplicate sources of truth
- [ ] Data flows are integrated/automated (or warehouse-synced via reverse ETL) — minimal manual re-entry between systems
- [ ] Reporting pulls from one governed dataset (not multiple conflicting dashboards)
- [ ] Routing + speed-to-lead automation actually enforces the SLA (measure, don't assume)
- [ ] Enrichment/intent **credit burn** is metered and capped to ICP-fit records
- [ ] Consent/suppression is honored across every tool that stores contact data
- [ ] **Tooling cost is benchmarked against the right denominator, not a flat % of ARR.** A flat "<15% of ARR" rule is misleading: early-stage teams run high (small ARR base), efficient scale-ups land far lower, and enterprise stacks vary widely. Evaluate stack spend against **gross margin, S&M efficiency (CAC payback, magic number), headcount leverage (ARR per GTM head), and measurable pipeline impact** — and kill tools with no attributable usage or pipeline contribution.
### 7. RevOps Metrics Dashboard
| Metric | Cadence | Target |
|--------|---------|--------|
| Pipeline coverage ratio | Weekly | 3-4x quarterly target |
| Win rate | Monthly | 20-30% |
| Average sales cycle | Monthly | Track trend, reduce 10% YoY |
| CAC payback | Monthly | < 12 months |
| Net revenue retention | Monthly | > 110% |
| Forecast accuracy | Monthly | ±10% |
| Speed to lead | Real-time | < 5 minutes |
| Pipeline created per rep | Weekly | Even distribution |
**Metric definitions (be explicit — most disagreements are definitional, not numeric):**
| Metric | Formula | Watch-outs |
|--------|---------|-----------|
| Pipeline coverage | `open weighted-or-raw pipeline closing this period / quota for the period` | State whether it's raw or weighted; 3–4× is a rough target only if win rate ≈ 25–33%. Coverage you can't *create in time* is fiction. |
| Stage conversion | `# reaching stage N+1 / # entering stage N` (cohort-based) | Cohort by *entry period*, not a point-in-time snapshot, or open deals distort it. Segment by ACV/source. |
| Win rate | `closed-won / (closed-won + closed-lost)` | Decide if "no decision/disqualified" counts as a loss — it changes the number a lot. |
| Sales-cycle length | `median(close_date − opportunity_created_at)` for closed-won | Use **median**, not mean (a few mega-deals skew the mean); segment by ACV. |
| Sales velocity | `(# open opps × avg deal value × win rate) / avg sales-cycle days` | The single best "are we speeding up or slowing down?" summary; track the trend per segment. |
| CAC payback | `CAC / (new MRR × gross margin %)` → months | Use *gross-margin-adjusted* new MRR, not raw revenue. Fully-loaded S&M for CAC. |
| Magic number | `(ΔARR over the quarter × 4) / prior-quarter S&M spend` | >0.75 → efficient, fund growth; <0.5 → fix efficiency before scaling spend. |
| GRR | `(starting ARR − churn − contraction) / starting ARR` | Caps at 100%; isolates pure retention from expansion. Healthy: >90% (SMB) to >95% (enterprise). |
| NRR | `(starting ARR − churn − contraction + expansion) / starting ARR` | Same cohort, no new logos. >110% is strong; report GRR alongside so expansion doesn't mask churn. |
**Reference SQL (Postgres/warehouse flavor — adapt table/column names):**
```sql
-- (a) Pipeline coverage for the current quarter (weighted), by owner
SELECT o.owner,
SUM(o.amount) AS raw_pipeline,
SUM(o.amount * s.stage_win_prob) AS weighted_pipeline,
q.quota,
ROUND(SUM(o.amount * s.stage_win_prob) / NULLIF(q.quota, 0), 2) AS weighted_coverage_x
FROM opportunities o
JOIN stage_probabilities s ON s.stage = o.stage -- your own historical win prob per stage
JOIN quotas q ON q.owner = o.owner AND q.period = date_trunc('quarter', CURRENT_DATE)
WHERE o.is_open
AND o.close_date >= date_trunc('quarter', CURRENT_DATE)
AND o.close_date < date_trunc('quarter', CURRENT_DATE) + INTERVAL '3 months'
GROUP BY o.owner, q.quota;
-- (b) Sales velocity + median cycle for last 90 days of closed-won, by segment
SELECT acv_band,
COUNT(*) FILTER (WHERE stage = 'Closed Won') AS won,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY (close_date - created_at)) FILTER (WHERE stage = 'Closed Won') AS median_cycle_days,
AVG(amount) FILTER (WHERE stage = 'Closed Won') AS avg_deal,
ROUND(100.0 * COUNT(*) FILTER (WHERE stage = 'Closed Won')
/ NULLIF(COUNT(*) FILTER (WHERE stage IN ('Closed Won','Closed Lost')), 0), 1) AS win_rate_pct
FROM opportunities
WHERE close_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY acv_band;
-- (c) NRR / GRR for a fixed starting cohort over the trailing 12 months
WITH base AS (
SELECT account_id, arr AS start_arr
FROM account_arr_snapshot
WHERE snapshot_date = CURRENT_DATE - INTERVAL '12 months'
),
now_arr AS (
SELECT account_id, arr AS end_arr
FROM account_arr_snapshot
WHERE snapshot_date = CURRENT_DATE
)
SELECT
ROUND(100.0 * SUM(LEAST(COALESCE(n.end_arr,0), b.start_arr)) / NULLIF(SUM(b.start_arr),0), 1) AS grr_pct,
ROUND(100.0 * SUM(COALESCE(n.end_arr,0)) / NULLIF(SUM(b.start_arr),0), 1) AS nrr_pct
FROM base b
LEFT JOIN now_arr n USING (account_id); -- accounts that fully churned have no row in now_arr
-- (d) New-pipeline / bookings sourced by channel (attribution), last quarter
SELECT source_channel,
COUNT(*) AS opps_created,
SUM(amount) FILTER (WHERE stage = 'Closed Won') AS won_arr,
SUM(amount) FILTER (WHERE is_open) AS open_pipeline
FROM opportunities
WHERE created_at >= date_trunc('quarter', CURRENT_DATE) - INTERVAL '3 months'
AND created_at < date_trunc('quarter', CURRENT_DATE)
GROUP BY source_channel
ORDER BY won_arr DESC NULLS LAST;
```
Govern these in one place (warehouse + dbt, or your BI semantic layer) so every team reads the same number; conflicting dashboards are the most common RevOps failure mode.
---
**Related skills:** for CRM data model, object hygiene, and automation see `crm-operations`; for top-of-funnel demand generation and channel strategy see `customer-acquisition`.