Uma Claude Skill que roda toda manhã, puxa toda conta que cruzou um threshold de risco de churn nas últimas 24 horas e posta um digest de uma página num canal do Slack: nome da conta, ARR em risco, o evento que dirigiu a mudança, o owner e uma próxima ação específica. Substitui o digest barulhento por email do Gainsight que a maioria dos CSMs já filtra para uma pasta, por algo apertado o suficiente para ler entre o standup e a primeira call com cliente.
O bundle do artifact vive em apps/web/public/artifacts/churn-risk-summarizer-claude/ — SKILL.md mais três arquivos de referência (1-risk-signal-weights.md, 2-sample-digest.md, 3-escalation-criteria-thresholds.md) que a Skill carrega em cada run.
Quando usar
Você tem Gainsight (ou uma plataforma de CS comparável) produzindo deltas de risk-score em que você confia no nível de direção, mas o digest existente é longo demais para ler ou genérico demais para agir. Você tem um time de CSMs que já se reúne toda manhã e se beneficiaria de uma leitura compartilhada de três minutos sobre o que mudou da noite para o dia. Você quer que o raciocínio por conta de “o que mudou e o que fazer a respeito” seja uniforme entre CSMs em vez de cada um inventar o próprio enquadramento.
A skill se encaixa quando o run diário aterrissa em 5-15 contas depois do filtro. Abaixo de 5, você não precisa de uma skill — leia a view do Gainsight direto. Acima de 15, os thresholds em references/3-escalation-criteria-thresholds.md precisam ser elevados antes do digest valer a pena rodar.
Quando NÃO usar
Você não tem risk scores em que confia. Garbage in, garbage out. Esta skill sumariza os scores que você dá pra ela; não computa nem corrige. Se seu modelo de risk do Gainsight está quebrado, conserte isso primeiro.
Você quer um trigger automatizado de ação do CSM. A skill é sinal read-only. Postar um digest num canal está bem; auto-criar tasks, mandar emails de playbook ou abrir casos está fora de escopo e vai te meter em problema rápido (veja “alert fatigue” abaixo).
Você quer copy voltado para o cliente. Nada do que a skill produz está liberado para enviar ao cliente. Trate todo output como interno.
Você quer análise longitudinal de churn. O prompt é calibrado para as últimas 24-168 horas. Para “o que aconteceu ao longo do Q3” use BI no warehouse do Gainsight.
Seu time de CSM tem duas pessoas. O custo de levantar isso supera o custo de um de vocês ler a view do Gainsight às 7am. Vale a pena a partir de quatro CSMs, onde a uniformidade de enquadramento começa a compor.
Setup
Defina o threshold. Decida o que “cruzou para risco de churn” significa concretamente. Os defaults em references/3-escalation-criteria-thresholds.md usam signal_score >= 12 para Red e uma queda de health_score de -15 para Amber. Edite esses números contra duas semanas de dados históricos antes de ir live.
Instale a Skill. Solte o bundle em ~/.claude/skills/churn-risk-summarizer/. Configure GAINSIGHT_TOKEN e SLACK_WEBHOOK_CHURN_DIGEST no seu env.
Configure o escopo. Edite references/3-escalation-criteria-thresholds.md com seu floor de min_arr (a maioria dos times usa $50k para um digest diário em canal) e sua lista de segments (a maioria dos times roda diário em enterprise + mid-market, semanal separado em SMB).
Calibre os pesos. Edite references/1-risk-signal-weights.md para combinar com a opinião do seu time sobre o que importa. Os pesos que vêm prontos são defaults razoáveis, não os seus defaults.
Agende o run. 7am horário local em dias de semana via cron, n8n ou um scheduled task do Claude. Posta no seu canal de CS.
Itere em signal-to-noise. As primeiras duas semanas vão ser barulhentas. Calibre um threshold por vez e observe dois dias de output antes de editar de novo. Não edite pesos e thresholds no mesmo run — você nunca vai saber qual mudança moveu o ponteiro.
O que a skill realmente faz
A Skill pega uma lista JSON de contas mais uma lista JSON de eventos de timeline da janela trailing (os schemas estão documentados em SKILL.md sob “Inputs”). Roda cinco passos sequenciais: agregação de sinal (soma de severity * weight por conta, com um cap por evento de 5 para impedir que uma escalation domine); bucketing baseado em threshold em Red, Amber e Watch; narrativa por conta aterrada nos summaries reais dos eventos (sem paráfrase — “active seats caíram de 142 para 89 ao longo de 7 dias”, não “engagement está caindo”); priorização por ARR descendente e depois data de renovação ascendente; e renderização para o layout literal em references/2-sample-digest.md.
A escolha de engenharia que vale destacar: pesos são explícitos e editáveis em vez de deixar o modelo decidir o que é importante por run. Quando um líder de CSM discorda do que apareceu, ele pode editar um número em references/1-risk-signal-weights.md e ver o efeito no digest de amanhã. Um julgamento do modelo por run não pode ser editado; só pode ser re-prompted, o que é mais difícil de auditar.
O campo Action tem um guard duro: se a ação sugerida contém engage, reach out, touch base, align ou socialize sem nomear uma pessoa ou artifact específico, ela é substituída por needs human review. Melhor silêncio do que barulho.
Realidade de custo
Um digest diário em 150 contas enterprise + mid-market com eventos da janela trailing roda aproximadamente 18-25k tokens de input (JSON de contas + JSON de eventos + os três arquivos de referência) e 1-3k tokens de output. No Claude Sonnet 4.5 com pricing de tabela ($3 / MTok input, $15 / MTok output) isso é cerca de $0.10-0.15 por run, ou $2-4 por mês rodando só em dias de semana. Negligível. O custo que realmente importa são os 10-15 minutos por semana do líder de CSM gastos calibrando pesos e thresholds no primeiro mês.
Se sua lista de contas está nos milhares em vez de centenas, faça batch por segmento e rode três ou quatro digests com escopo em vez de um — o custo por token é o mesmo mas a scannability por digest fica intacta.
Métrica de sucesso
Acompanhe o percentual de contas do bucket Red que têm uma ação logada por CSM dentro de 48 horas do digest. Se fica acima de 70%, o digest está fazendo seu trabalho: o bucket Red é curto o suficiente e confiável o suficiente para que os owners ajam nele. Se cai abaixo de 50%, ou os thresholds estão frouxos demais (o bucket Red está transbordando e sendo ignorado) ou as ações sugeridas estão genéricas demais (colapso de especificidade de Action — veja pontos de atenção). Não otimize para “mais contas surfaceadas” — menos contas Red com melhor evidência é a meta.
vs alternativas
Gainsight Health Scorecards 2.0 + email de digest nativo. O digest nativo tem o dado mas não a camada editorial — toda conta em risco recebe o mesmo template, sem narrativa por conta do driver nem próxima ação específica. Funciona como sistema de registro; falha como coisa que CSMs de fato abrem. Escolha isso se seu time prefere menos partes móveis e tem headcount para ler a versão longa.
Dashboards de BI customizados sobre o warehouse do Gainsight (Looker, Mode, Hex). Melhores para perguntas transversais tipo “me mostra retenção por segmento”, piores para “o que o time deve fazer hoje”. Um dashboard que requer um clique é um dashboard que não vai ser clicado às 7am. Rode os dois — o dashboard para review mensal, a skill para ação diária.
Review manual de CSM na segunda de manhã. O que a maioria dos times faz hoje. Funciona na escala de quatro CSMs, quebra depois disso porque cada CSM inventa seu próprio enquadramento de “o que é arriscado”. A skill existe para dar ao time um enquadramento compartilhado contra o qual eles podem argumentar editando o arquivo de pesos, em vez de argumentar uns com os outros no standup.
Pontos de atenção
Alert fatigue. Um digest que consistentemente excede 15 contas vai pra filtro de pasta dentro de uma semana. Guard: hard-cap em 15 com contagens honestas de overflow no rodapé, e se Red excede o cap em três runs consecutivos prepend um aviso de que o threshold pode estar frouxo demais. Implementado em references/3-escalation-criteria-thresholds.md sob “Self-tuning trigger”.
Enxurrada de falsos positivos. Um peso de event-type miscalibrado pode produzir um bucket Red dominado por, digamos, toda conta com uma escalation de suporte recente. Guard: o rodapé do digest inclui uma linha de percentual de mix de event-type para que o time enxergue um sinal dominando antes da confiança erodir. Exemplo trabalhado em references/2-sample-digest.md (“Event-type mix this week:”).
Drift de signal weighting. O arquivo de pesos fica obsoleto à medida que o produto e a base de clientes evoluem. Guard: a skill emite o SHA curto de references/1-risk-signal-weights.md no rodapé do digest. Se o hash não mudou em 90 dias, o digest prepend uma nudge de recalibração.
Owner desatualizado. Um digest que pinga o CSM errado é pior do que nenhum digest. Guard: contas cujo owner_email não pode ser resolvido aparecem sob um bucket separado *Ownership broken (n)* com um link para o editor de ownership do Gainsight — não têm permissão de cair silenciosamente em Red ou Amber.
Stack
Gainsight — fonte de risk-score, contexto de conta, eventos de timeline
Claude (Sonnet 4.5) — síntese, bucketing, draft de ação
Slack — canal de destino; output em mrkdwn, sem anexos
Cron / n8n / scheduled tasks do Claude — trigger diário às 7am
---
name: churn-risk-summarizer
description: Produce a daily (or weekly) digest of accounts that crossed a churn-risk threshold in the last N hours. Aggregates Gainsight risk-score deltas, recent timeline events, and ARR exposure into a tightly bucketed Slack-ready summary that names the change driver and one specific next action per account.
---
# Churn-risk summarizer
## When to invoke
Run on a schedule (typically 7am local, daily) or on demand to generate a prioritized list of accounts that crossed a churn-risk threshold in the trailing window. Input is a Gainsight account list with risk signals plus recent timeline activity; output is a bucketed digest sized for a CSM team to read in under three minutes.
Do NOT invoke this skill for:
- Triggering automated CSM actions (creating tasks, sending playbook emails, opening cases). The digest is read-only signal — humans decide the next action.
- Any customer-facing communication. Nothing this skill produces is cleared for sending to the customer; treat all output as internal.
- Backfilling historical churn analysis (the prompt is tuned for the trailing 24-168 hours). For longitudinal review, use BI on the Gainsight warehouse instead.
- Risk scoring itself. The skill summarizes scores it is given; it does not compute or reweight them.
## Inputs
- Required: `accounts` — JSON array of account records with at minimum `id`, `name`, `arr`, `risk_score_current`, `risk_score_prior`, `health_score_current`, `health_score_prior`, `owner_email`, `segment`, `renewal_date`.
- Required: `events` — JSON array of timeline events for the same accounts in the trailing window. Each event needs `account_id`, `type` (one of `usage_drop`, `support_escalation`, `sponsor_change`, `qbr_missed`, `nps_detractor`, `contract_renegotiation`, `exec_disengagement`), `severity` (1-5), `occurred_at`, `summary`.
- Optional: `window_hours` — lookback window. Defaults to 24.
- Optional: `min_arr` — drop accounts below this ARR floor. Defaults to 0 (no floor).
- Optional: `segments` — filter to a list of segments (e.g. `["enterprise", "mid-market"]`). Defaults to all.
- Optional: `cap` — maximum accounts to surface in the digest body. Defaults to 15. Overflow goes into a "+N more" link.
## Reference files
Read these from `references/` before generating the digest. They encode the team's risk-weighting opinion and the digest format. Without them, the output is generic.
- `references/1-risk-signal-weights.md` — per-event-type weighting config the skill applies when ranking accounts within a bucket.
- `references/2-sample-digest.md` — the literal Slack-ready digest format the skill emits, with a worked example.
- `references/3-escalation-criteria-thresholds.md` — the bucket thresholds (red / amber / watch) and the rules for when a single signal is enough to escalate by itself.
## Method
Run these five steps in order. Do not parallelize: bucketing depends on aggregation, narrative depends on bucketing.
### 1. Signal aggregation
For each account, collect the trailing-window events from `events`, sort by `occurred_at` descending, and compute a per-account `signal_score` as the sum of `severity * weight` per event using the weights in `references/1-risk-signal-weights.md`. Cap any single event's contribution at 5 — one escalation should not single-handedly dominate the score unless the weights file says so explicitly.
The reason for explicit weighting (rather than letting the model "decide what's important"): weights are auditable. When a CSM lead disagrees with what got surfaced, they can edit one number in the weights file. A per-run model judgment cannot be edited.
### 2. Threshold-based bucketing
Apply the thresholds in `references/3-escalation-criteria-thresholds.md` to assign each account to exactly one bucket:
- **Red** — risk_score crossed the explicit churn-risk line, OR signal_score >= the red threshold, OR a single event is on the always-escalate list (e.g. `exec_disengagement` at severity 5).
- **Amber** — health_score dropped by more than the amber delta, OR signal_score is between amber and red.
- **Watch** — any other accounts that crossed *into* the band but do not meet amber criteria.
If `min_arr` or `segments` filters drop an account below the floor, exclude it from all buckets — but record the count for the footer.
### 3. Per-account evidence-grounded narrative
For each account in Red and Amber (skip Watch — it gets a count-only line), compose:
- One-line change driver naming the dominant event, never paraphrased away from `events[].summary`. If the dominant event was a usage drop, say "active seats fell from 142 to 89 over 7 days," not "engagement is declining."
- One concrete suggested action, formatted as a verb plus a named artifact (a meeting, a person, a doc). Examples: "Call the CFO before Friday's renewal kickoff." "Open a case with support to triage the open P1." "Forward last week's QBR deck to the new VP of Eng."
- If no concrete action can be supported from the evidence, output `needs human review` rather than padding. Vague actions are the primary failure mode the digest exists to avoid.
### 4. Prioritization
Within each bucket, sort by ARR descending, breaking ties by `renewal_date` ascending (closer renewals first). Apply `cap` to the combined Red + Amber list. If the cap drops accounts, surface them only as a count and a link to the full Gainsight saved view.
### 5. Format and emit
Render to the layout in `references/2-sample-digest.md`. The output is a single Slack-mrkdwn block plus a fallback plaintext copy. Do not include tables, attachments, or threads — the digest must be scannable in the channel without expanding anything.
## Output format
```markdown
*Daily churn-risk digest — {YYYY-MM-DD}*
*Red ({n_red})* — act this week
- *{Account name}* — ${ARR}k ARR · owner @{owner_handle} · renewal {renewal_date}
Driver: {one-line driver from evidence}
Action: {verb + named artifact}
- ...
*Amber ({n_amber})* — review by Friday
- *{Account name}* — ${ARR}k ARR · owner @{owner_handle} · renewal {renewal_date}
Driver: {one-line driver}
Action: {verb + named artifact, or `needs human review`}
- ...
*Watch ({n_watch})* — no action required, tracking only.
{count summary, no per-account detail}
_Filtered out: {n_below_floor} below ${min_arr}k · {n_below_segment} outside segment._
_Capped at {cap} of {n_red + n_amber} qualifying. Full list: {gainsight_saved_view_url}_
```
## Watch-outs
- **Alert fatigue.** If the digest carries more than ~15 accounts day after day, owners stop opening it. Guard: enforce `cap` strictly, and if Red exceeds cap on three consecutive runs, prepend a `_Threshold may be too loose — last 3 runs averaged {n} Red. Consider raising the red threshold in references/3-escalation-criteria-thresholds.md._` warning. Do not silently truncate without flagging.
- **False-positive flooding.** Any single event type producing more than 30% of Red accounts in a week is a signal that its weight is miscalibrated. Guard: at the end of the digest, include a one-line diagnostic — `_Event-type mix this week: usage_drop 18%, support_escalation 22%, ..._` — so the team can spot one signal dominating before it erodes trust in the digest.
- **Signal weighting drift.** Weights in the references file go stale as the product and customer base change. Guard: include the SHA-256 (first 7 chars) of `references/1-risk-signal-weights.md` in the digest footer. If the footer hash hasn't changed in 90 days, the digest prepends `_Weights file last touched 90+ days ago. Time to recalibrate._`
- **Owner staleness.** If `owner_email` is empty or maps to a former employee, the ping goes to the wrong person and the action does not happen. Guard: any account whose owner handle cannot be resolved gets surfaced under `*Ownership broken ({n})*` instead of Red/Amber, with a link to the Gainsight account ownership editor.
- **Action specificity collapse.** Under load, the model defaults to generic "engage stakeholder" suggestions. Guard: post-process the Action field with a literal substring check — if the action contains any of `engage`, `reach out`, `touch base`, `align`, `socialize` without a named person or artifact, replace it with `needs human review`. Better silence than noise.
# Risk signal weights — TEMPLATE
> Replace these weights with values your CSM lead has signed off on.
> The skill multiplies `severity` (1-5) by the weight below to get
> per-event contribution to `signal_score`. Edit one number at a time
> and watch the next two digests before editing again.
## Per-event-type weights
| Event type | Weight | Notes |
|-------------------------|-------:|-----------------------------------------------------------------|
| `exec_disengagement` | 5.0 | Sponsor stops attending QBRs / unread emails for 30+ days |
| `sponsor_change` | 4.0 | Champion left or moved internally; new owner not yet onboarded |
| `contract_renegotiation`| 3.5 | Procurement opened a contract review outside the renewal window |
| `support_escalation` | 3.0 | P1 case open > 5 business days, or 3+ P2s in 14 days |
| `usage_drop` | 3.0 | Active seats / API calls / features-used down >25% over 14 days |
| `nps_detractor` | 2.0 | NPS <= 6 from any buying-committee role in the last 30 days |
| `qbr_missed` | 2.0 | Cancelled or no-show with no reschedule within 14 days |
## Always-escalate single signals
These trigger Red regardless of `signal_score`. The skill should treat them as a hard override, not a soft boost.
- `exec_disengagement` at severity 5
- `sponsor_change` at severity 4-5 when the renewal date is within 90 days
- `contract_renegotiation` at any severity when ARR > 250k
## Per-event contribution cap
A single event contributes at most 5.0 to `signal_score` regardless of `severity * weight`. This prevents one severity-5 sponsor change from single-handedly flooding the digest with one account at the expense of two genuinely declining ones.
## Weight calibration log
Append every change here so the next person editing this file can see why the numbers are what they are. Format: `YYYY-MM-DD — change — reason`.
- {YYYY-MM-DD} — initial weights — placeholder, replace with team-tuned values
## Last edited
{YYYY-MM-DD}
# Sample digest — worked example
> The skill emits this exact format, Slack-mrkdwn flavored. Treat this
> file as the contract: if you change the layout, change it here first
> and the skill follows. Do not let the model improvise structure.
## Worked example output
```
*Daily churn-risk digest — 2025-11-04*
*Red (3)* — act this week
- *Acme Robotics* — $480k ARR · owner @nadia · renewal 2025-12-18
Driver: VP Eng skipped two scheduled syncs and an automation pilot was paused on 10-29.
Action: Get Nadia a 30-min slot with the new VP Eng before Friday's renewal kickoff.
- *Northwind Logistics* — $310k ARR · owner @marcus · renewal 2026-01-09
Driver: Active seats fell from 142 to 89 over the last 7 days; finance opened a contract review.
Action: Open a discount-modeling thread with the deal desk before the procurement call on 11-07.
- *Globex Health* — $265k ARR · owner @priya · renewal 2026-02-22
Driver: P1 outage case open since 10-30 with no first-response SLA met.
Action: Escalate the open P1 to support leadership and brief Priya before her standing customer call.
*Amber (4)* — review by Friday
- *Initech* — $180k ARR · owner @marcus · renewal 2026-03-14
Driver: Sponsor moved to a new role last week; new owner has not been introduced.
Action: Send the QBR deck and offer a 15-min intro call with the new sponsor.
- *Vandelay Imports* — $140k ARR · owner @nadia · renewal 2026-01-30
Driver: Three P2 cases opened in the last 10 days, all on the reporting module.
Action: needs human review
- *Soylent Foods* — $115k ARR · owner @priya · renewal 2026-04-02
Driver: NPS dropped to 4 from the Director of Ops on 10-31.
Action: Forward the survey verbatim to Priya and request a follow-up 1:1 with the Director.
- *Pied Piper* — $95k ARR · owner @marcus · renewal 2026-02-11
Driver: QBR cancelled 10-28, no reschedule.
Action: Propose three slots for next week and copy the original sponsor.
*Watch (6)* — no action required, tracking only.
6 accounts crossed into the watch band; signal not strong enough for action this week.
_Filtered out: 2 below $50k · 0 outside segment._
_Capped at 13 of 13 qualifying. Full list: https://gainsight.example.com/views/churn-risk-trailing-24h_
_Event-type mix this week: usage_drop 24%, support_escalation 28%, sponsor_change 14%, qbr_missed 12%, nps_detractor 10%, exec_disengagement 6%, contract_renegotiation 6%._
_Weights file: 1-risk-signal-weights.md @ a3f9c12_
```
## Notes for the skill
- Account names are bolded with single asterisks (Slack-mrkdwn).
- The `Action:` line is the *only* place where a generic phrase (`engage`, `align`, `socialize`, `reach out`, `touch base`) is rejected and replaced with `needs human review`.
- The Watch bucket never emits per-account lines. Only the count.
- The footer carries three diagnostics — filter counts, event-type mix, and the weights-file hash — that exist to make miscalibration visible early. Do not drop them to save lines.
# Escalation criteria thresholds — TEMPLATE
> Replace these defaults with the values your CSM lead has signed off
> on. Aim for 5-15 total Red+Amber accounts per daily run; if you are
> consistently above or below, the thresholds are wrong, not the team.
## Bucket definitions
An account lands in exactly one bucket per run. The skill evaluates in this order and stops at the first match.
### Red — act this week
ANY of the following:
- `risk_score_current` crossed the explicit churn-risk line set in Gainsight (e.g. moved from "Medium" to "High", or numeric score crossed below 40), AND `risk_score_prior` was on the safe side of that line within the trailing window.
- `signal_score` >= **12.0** (sum of `severity * weight` across trailing-window events, per `1-risk-signal-weights.md`).
- A single event matches the always-escalate list in `1-risk-signal-weights.md` ("Always-escalate single signals").
### Amber — review by Friday
ANY of the following, and NOT already Red:
- `health_score_current - health_score_prior` <= **-15** in the trailing window.
- `signal_score` between **6.0** and **12.0**.
### Watch — count only
Crossed into the band (any negative movement on either score) but does not meet Amber criteria. Surfaced as a count only.
## Filters
Applied before bucketing. Filtered accounts are excluded from all buckets and reported in the footer.
- `min_arr` — drop accounts with `arr` < this value. Default **0**. Most teams that send to a channel set this to **50** (k$) to keep the digest scannable.
- `segments` — restrict to a list of `segment` values. Default: all segments. Most teams running a daily digest restrict to `["enterprise", "mid-market"]` and run a separate weekly digest for SMB to keep the daily list focused on accounts that justify a human-touch action.
## Cap and overflow
`cap` = **15** by default. After Red+Amber are sorted by ARR descending, anything beyond the cap goes into the footer count + a link to the saved Gainsight view. Do not silently drop accounts — the count must always be honest.
## Self-tuning trigger
If Red exceeds `cap` on three consecutive runs, the skill prepends a warning to the digest noting the threshold may be too loose. The skill does NOT auto-edit this file. Threshold edits are a human decision; the skill only surfaces the signal.
## Threshold change log
Append every change so the next person editing this file can see why the numbers are what they are. Format: `YYYY-MM-DD — change — reason`.
- {YYYY-MM-DD} — initial thresholds — placeholder, replace with team-tuned values
## Last edited
{YYYY-MM-DD}