microsoft/account-risk-early-warning
Identifies accounts showing warning signs of churn by analyzing activity trends, support cases, and engagement signals. Scores risk and prioritizes intervention targets. Use when user asks "which accounts are at risk", "churn risk analysis", "find accounts that might leave", "customer health check", "at-risk customers", "retention warning signs", or "account health score".
npx skills add https://github.com/microsoft/dataverse-business-skills --skill account-risk-early-warning
Retaining existing customers is more cost-effective than acquiring new ones. This skill monitors key accounts for early warning signals that indicate potential churn or relationship issues, enabling proactive intervention before problems escalate.
When user asks "Which of my top accounts are showing warning signs?":
1.1 Define Account Set:
Options:
A) All active accounts owned by user
B) Specific account list (e.g., enterprise tier)
C) Accounts with revenue above threshold
D) Accounts up for renewal in next X months
1.2 Query Target Accounts:
SELECT accountid, name, revenue, numberofemployees, industrycode,
createdon, ownerid, customertypecode, territoryid,
openrevenue, openrevenue_date
FROM account
-- Note: openrevenue and openrevenue_date are rollup fields that may not exist in all orgs.
-- If absent, calculate open pipeline value by querying the opportunity table directly.
WHERE statecode = 0
AND ownerid = '[current_user_id]' -- or specific criteria
ORDER BY revenue DESC
Important: Dataverse SQL Limitations
Dataverse SQL does NOT support: subqueries, DATEADD(), GETUTCDATE(), HAVING, DISTINCT, UNION, CASE statements.
Use separate queries and calculate date filters programmatically (e.g., calculate '2025-09-01' for 6 months ago).
2.1 Activity Trend Analysis
Query recent activities for each account (run separately per account):
SELECT activityid, activitytypecode, createdon, statecode
FROM activitypointer
WHERE regardingobjectid = '[accountid]'
AND createdon > '2025-09-01'
ORDER BY createdon DESC
Calculate Activity Metrics:
For each account:
- Total activities (last 6 months)
- Activities per month trend
- Activity types breakdown
- Days since last activity
- Comparison to account's historical average
Activity Risk Indicators:
| Signal | Warning | Critical |
|--------|---------|----------|
| Days Since Last Activity | 30+ days | 60+ days |
| Month-over-Month Decline | 25%+ decline | 50%+ decline |
| No Meetings/Calls | 45+ days | 90+ days |
| Only Automated Emails | 30+ days | 60+ days |
2.2 Support Case Pattern Analysis
Query recent cases (run per account, calculate date filter programmatically):
SELECT incidentid, title, createdon, prioritycode, severitycode,
statecode, statuscode, caseorigincode, customersatisfactioncode,
msdyn_casesentiment, escalatedon
FROM incident
WHERE customerid = '[accountid]'
AND createdon > '2025-09-01'
ORDER BY createdon DESC
Calculate Case Metrics:
For each account:
- Total cases (last 6 months)
- Cases per month trend
- Case severity distribution
- Average resolution time
- Escalation count
- Customer satisfaction scores (if available)
- Sentiment analysis (msdyn_casesentiment)
Case Risk Indicators:
| Signal | Warning | Critical |
|--------|---------|----------|
| Case Volume Increase | 50%+ increase | 100%+ increase |
| High Severity Cases | 2+ in 30 days | 5+ in 30 days |
| Escalated Cases | 1 in 60 days | 2+ in 60 days |
| Negative Sentiment | Score 9 (Slightly negative) | Score 7-8 (Very negative / Negative) |
| Low Satisfaction | Score 2-3 | Score 1 (Very Dissatisfied) |
| Unresolved Cases | 3+ open > 7 days | 5+ open > 14 days |
2.3 Opportunity Velocity Analysis
Query opportunity history (per account, calculate date filter programmatically):
SELECT opportunityid, name, estimatedvalue, actualvalue,
statecode, statuscode, createdon, actualclosedate,
salesstage, msdyn_forecastcategory
FROM opportunity
WHERE accountid = '[accountid]'
AND createdon > '2024-03-01'
ORDER BY createdon DESC
Calculate Opportunity Metrics:
For each account:
- New opportunities (last 6 months vs prior 6 months)
- Win rate trend
- Average deal size trend
- Pipeline coverage
- Time since last won deal
- Lost opportunities (recent)
Opportunity Risk Indicators:
| Signal | Warning | Critical |
|--------|---------|----------|
| No New Opportunities | 90+ days | 180+ days |
| Declining Win Rate | 20%+ decline | 50%+ decline |
| Declining Deal Size | 25%+ decline | 50%+ decline |
| Recent Lost Deals | 1 in 60 days | 2+ in 60 days |
| Stalled Pipeline | 60+ days no movement | 90+ days |
2.4 Engagement Pattern Analysis
Analyze contact engagement:
SELECT c.contactid, c.fullname, c.jobtitle, c.accountrolecode
FROM contact c
WHERE c.accountid IN ([target account ids])
AND c.statecode = 0
SELECT a.regardingobjectid, COUNT(*) as activity_count,
MAX(a.createdon) as last_activity
FROM activitypointer a
JOIN contact c ON a.regardingobjectid = c.contactid
WHERE c.accountid IN ([target account ids])
AND a.createdon >= '[6_months_ago]'
GROUP BY a.regardingobjectid
Engagement Risk Indicators:
| Signal | Warning | Critical |
|--------|---------|----------|
| Key Contact Disengaged | 45+ days no response | 90+ days |
| Champion Gone Dark | 30+ days | 60+ days |
| Executive Engagement Drop | 50%+ decline | 75%+ decline |
| New Decision Maker | Not yet engaged | 60+ days not engaged |
| Contact Left Company | Detected | Champion left |
2.5 Relationship Signals from Notes
Analyze annotations and activity descriptions:
SELECT a.objectid, a.subject, a.notetext, a.createdon
FROM annotation a
WHERE a.objecttypecode = 'account'
AND a.objectid IN ([target account ids])
AND a.createdon >= '[6_months_ago]'
ORDER BY a.createdon DESC
Keyword Detection:
Look for risk keywords in notes:
2.6 Renewal and Contract Signals
If contract/renewal data available:
Query opportunities or custom entities for:
- Upcoming renewal dates
- Contract end dates
- Renewal discussions (or lack thereof)
Renewal Risk Indicators:
| Signal | Warning | Critical |
|--------|---------|----------|
| Renewal in 90 days | No discussion started | Negative feedback received |
| Renewal in 60 days | No commitment | Competitor being evaluated |
| Renewal in 30 days | Not verbal confirmed | At risk / declining |
Risk Score Model (0-100, higher = more risk):
| Risk Category | Weight | Max Points |
|---------------|--------|------------|
| Activity Decline | 20% | 20 |
| Support Case Patterns | 25% | 25 |
| Opportunity Velocity | 20% | 20 |
| Engagement Patterns | 20% | 20 |
| Relationship Signals | 15% | 15 |
Score Interpretation:
Sort accounts by:
Calculate Priority Score:
priority = risk_score * 0.5 + revenue_weight * 0.3 + renewal_urgency * 0.2
Where:
- risk_score: 0-100 from Step 3
- revenue_weight: Normalized account revenue
- renewal_urgency: Days until renewal (inverted scale)
Output Format:
ACCOUNT RISK EARLY WARNING REPORT
════════════════════════════════════════════════════
Generated: [Date]
Scope: [User]'s Accounts
Accounts Analyzed: [N]
════════════════════════════════════════════════════
RISK SUMMARY
════════════════════════════════════════════════════
Critical Risk (76-100): [N] accounts $[revenue at risk]
At Risk (51-75): [N] accounts $[revenue at risk]
Monitor (26-50): [N] accounts $[revenue at risk]
Healthy (0-25): [N] accounts $[revenue value]
TOTAL REVENUE AT RISK: $[sum of Critical + At Risk]
════════════════════════════════════════════════════
PRIORITY INTERVENTION LIST
════════════════════════════════════════════════════
1. 🔴 CONTOSO CORPORATION
Risk Score: 85/100 (Critical)
Annual Revenue: $500,000
Renewal: 45 days
─────────────────────────────────────────────────
WARNING SIGNALS:
⚠️ Activity Decline: 67% fewer touchpoints vs prior quarter
⚠️ Support Cases: 8 cases in 30 days (up 300% from average)
⚠️ Escalation: 2 escalated cases in past month
⚠️ Sentiment: Case sentiment trending negative (avg 7.5)
⚠️ Competitor: "Evaluating alternatives" mentioned in notes
⚠️ Contact: VP Champion hasn't responded in 45 days
DETAILED ANALYSIS:
Activity Trend:
• 6 months ago: 12 activities/month
• Current: 4 activities/month
• Trend: ↓ 67% decline
Support Cases:
• Total (6 mo): 15 cases
• Last 30 days: 8 cases (spike)
• High Severity: 3 cases
• Avg Resolution: 5.2 days (above SLA)
Opportunity Status:
• No new opportunities in 120 days
• Last won deal: 8 months ago
• Pipeline: $0 (no active deals)
Key Contacts:
• Sarah Chen (VP Ops) - Last contact: 45 days ago ⚠️
• John Smith (IT Dir) - Last contact: 12 days ago ✓
RECOMMENDED INTERVENTIONS:
Priority 1 (Immediate):
📞 Executive outreach from sales leadership to Sarah Chen
• Acknowledge support issues
• Request relationship review meeting
• Bring solutions, not sales pitch
Priority 2 (This Week):
📋 Support case review with CS team
• Identify root cause of case spike
• Escalate to product/engineering if needed
• Prepare remediation plan
Priority 3 (Within 2 Weeks):
📅 Renewal discussion meeting
• Don't wait - engage on renewal now
• Address concerns before they finalize decision
• Consider retention incentives if needed
─────────────────────────────────────────────────
2. 🟠 FABRIKAM INDUSTRIES
Risk Score: 62/100 (At Risk)
Annual Revenue: $250,000
Renewal: 90 days
─────────────────────────────────────────────────
WARNING SIGNALS:
⚠️ Champion Left: Primary contact left company 30 days ago
⚠️ New Decision Maker: Replacement not yet engaged
⚠️ Activity: 45 days since meaningful engagement
RECOMMENDED INTERVENTIONS:
Priority 1: Identify and engage new decision maker
• Research LinkedIn for replacement
• Get warm intro from remaining contacts
• Schedule introductory meeting
[Continue for additional at-risk accounts...]
For each high-priority account, offer to create:
Use create_record with tablename: task
{
"subject": "⚠️ Risk Intervention: [Account Name]",
"description": "Risk Score: [X]/100\n\nKey Warning Signals:\n- [Signal 1]\n- [Signal 2]\n\nRecommended Actions:\n1. [Action 1]\n2. [Action 2]",
"regardingobjectid": "[accountid]",
"scheduledend": "[today or tomorrow]",
"prioritycode": 1 (High)
}
Add note to account record:
Use create_record with tablename: annotation
{
"subject": "Risk Assessment - [Date]",
"notetext": "Account flagged as [Risk Level].\n\nWarning Signals:\n[Details]\n\nIntervention Plan:\n[Actions]",
"objectid": "[accountid]",
"objecttypecode": "account"
}
| Table | Purpose |
|-------|---------|
| account | Primary entity for risk analysis |
| activitypointer | Activity trend analysis |
| phonecall | Engagement tracking |
| appointment | Meeting frequency |
| email | Communication patterns |
| incident | Support case patterns |
| opportunity | Revenue velocity |
| contact | Stakeholder engagement |
| annotation | Notes for signal detection |
| task | Create intervention tasks |
account:
revenue (MONEY) - Account value for prioritizationownerid (OWNER) - Account owner for filteringcreatedon (DATETIME) - Tenure calculationcustomertypecode (CHOICE) - Relationship typeopenrevenue (MONEY) - Total open pipeline value *(rollup field; availability depends on org configuration)*msdyn_accountkpiid (LOOKUP → msdyn_accountkpiitem) - Relationship analytics KPIstatecode (STATE) - Active(0), Inactive(1)msdyn_accountkpiitem (Sales Insights - Relationship Analytics):
msdyn_relationshiphealthscorevalue (INT) - Health score (0-100)msdyn_relationshiphealthscorestate (CHOICE) - Good(0), Fair(1), Poor(2)msdyn_relationshiphealthtrend (CHOICE) - Improving(0), Steady(1), Declining(2), Not enough info(3)msdyn_emailssent (INT) - Outgoing emails countmsdyn_emailsreceived (INT) - Incoming emails countmsdyn_phonecallsmade (INT) - Outbound calls countmsdyn_phonecallsreceived (INT) - Inbound calls countmsdyn_meetingssent (INT) - Meetings scheduled countmsdyn_lastactivitybyteam (DATETIME) - Last team outreachmsdyn_nextactivitybyteam (DATETIME) - Next scheduled activitymsdyn_facetimewithcustomer (DURATION) - Total meeting timemsdyn_timespentbyteam (DURATION) - Total time investedmsdyn_averagefirstresponsetimebyusinhrs (FLOAT) - Avg response time (hours)incident:
prioritycode (CHOICE) - High(1), Normal(2), Low(3)severitycode (CHOICE) - Severity levelcasetypecode (CHOICE) - Question(1), Problem(2), Request(3)caseorigincode (CHOICE) - Source channelcustomersatisfactioncode (CHOICE) - Very Dissatisfied(1), Dissatisfied(2), Neutral(3), Satisfied(4), Very Satisfied(5)msdyn_casesentiment (CHOICE) - Sentiment scale (lower = more negative): Very negative(7), Negative(8), Slightly negative(9), Neutral(10), Slightly positive(11), Positive(12), Very positive(13)escalatedon (DATETIME) - Escalation trackingstatecode (STATE) - Active(0), Resolved(1), Cancelled(2)statuscode (STATUS) - In Progress(1), On Hold(2), Waiting(3), Researching(4) [Active]; Problem Solved(5), Info Provided(1000) [Resolved]; Cancelled(6), Merged(2000) [Cancelled]activitypointer:
activitytypecode (NVARCHAR) - Type: phonecall, email, appointment, taskcreatedon (DATETIME) - Activity dateregardingobjectid (LOOKUP) - Polymorphic link to account, contact, etc.statecode (STATE) - Open(0), Completed(1), Canceled(2), Scheduled(3-appointments)| Signal Category | Default Weight | Adjustable Range |
|-----------------|----------------|------------------|
| Activity Decline | 20% | 10-30% |
| Support Cases | 25% | 15-35% |
| Opportunity Velocity | 20% | 10-30% |
| Engagement Patterns | 20% | 10-30% |
| Relationship Signals | 15% | 10-25% |
User says: "Which of my accounts are at risk?"
Actions:
Result:
ACCOUNT RISK SUMMARY
Critical (2): Immediate intervention required
Warning (5): Schedule check-in this week
Monitor (8): Watch for changes
Healthy (35): No action needed
CRITICAL ACCOUNTS:
1. Contoso Ltd - Risk Score: 85/100
- 60+ days since last activity
- 3 escalated support cases
- Renewal in 45 days
ACTION: Executive outreach immediately
2. Fabrikam Inc - Risk Score: 78/100
- Activity declined 70% vs prior quarter
- Champion contact left company
ACTION: Re-establish relationships
User says: "Check the health of the Northwind account"
Actions:
Result:
NORTHWIND TRADERS - HEALTH ASSESSMENT
Overall Risk: WARNING (62/100)
ACTIVITY ANALYSIS:
- Last interaction: 28 days ago (email)
- Trend: Declining (45% fewer touchpoints vs. prior 90 days)
SUPPORT ANALYSIS:
- Open cases: 2 (1 high priority)
- Recent escalation: Yes (3 days ago)
- Sentiment: Slightly negative
OPPORTUNITY ANALYSIS:
- No new opportunities in 6 months
- Last deal: Won 8 months ago
RECOMMENDATION:
Schedule customer success call to address open cases and explore expansion opportunities.
User says: "Show me accounts with renewals coming up that are at risk"
Actions:
Result:
AT-RISK RENEWALS (Next 90 Days):
1. Alpine Ski House - $150K ARR - Renews in 30 days
Risk: High engagement drop + unresolved escalation
2. Tailspin Toys - $80K ARR - Renews in 60 days
Risk: Budget freeze mentioned in recent call notes
Cause: Sales Insights or Relationship Analytics not enabled
Solution:
Cause: Thresholds too sensitive for organization's engagement patterns
Solution:
Cause: Customer service not using Dynamics 365 for cases
Solution:
Take microsoft/account-risk-early-warning from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.