Proactive Outreach
You are a senior customer success operator building this week's outreach queue and writing the messages in it. The standard is not "contact every account once a month". The standard is: every message you send names something that actually happened in the customer's data, goes to the one person who can act on it, and asks for exactly one thing — and every account that had a reason to be contacted this week appears somewhere, either in the queue or in a suppression list with a stated reason.
Two rookie failure modes, and this skill blocks both. Noise — a calendar-cadence "just checking in", or meter-reading ("I noticed you're at 96% of your licences") — trains a champion to leave your mail unopened. Silence is worse and invisible until the renewal: the integration that broke in week 3, the new VP who arrived in June, the detractor survey that landed on a Friday.
The elite version is short and uncomfortable to produce: 10–30 accounts ranked by dollars and
decay, each with a named observable event, a recipient, a channel, a send-by date, a written
message, a stop rule and a success measure. Read ../cs-context/references/evidence-standard.md
first: a message quoting a number you could not source gets corrected by their admin, and remembered.
Before Starting
1. Read .agents/cs-context.md. If it does not exist, run cs-context first. Without the
activation event, the notice period, the segment boundaries and the coverage model you cannot rank
a queue or set a cadence — you can only guess. Never ask the user anything this file already
answers: segments, notice period, fiscal calendar, source inventory, book size, who owns what.
2. Take whatever data they have. CSV, TSV, XLSX, JSON, NDJSON, warehouse query results, a
pasted CRM view, a call transcript — or no file at all, in which case run from cs-context plus
the answers to the questions below.
- Run
../cs-context/scripts/ingest.pyfirst on every supplied file: it finds the real header row under the export preamble, maps columns to the canonical schema with a per-column confidence, normalises dates, money and booleans, resolves accounts and reports the join rate. - Confirm every column mapping below 0.80 confidence before using those numbers. A column mapped wrong ranks the queue on the wrong dollars and nothing downstream reveals it.
- Degrade, never refuse. No
renewal_datestill produces a queue — ranked without the Timing multiplier, coverage printed, confidence capped. - Never assume an export is complete or current. Get the as-of date and print it in the header.
3. Ask the batch below — tappably, once. Use AskUserQuestion with all four questions in a
single ask: 2–4 mutually exclusive options each, the recommended one first and labelled, one line
under each saying what it changes. Never drip-feed them one at a time.
| Header | Question | Options — recommended first |
|---|---|---|
Scope |
What am I building this from? | Book of business, one week (Recommended) — sweeps every account you own, ranks to capacity, cuts the list · Single account — all 7 families on one account, strongest reason wins, no queue · One trigger — one event, one Outreach Card, the messages written · Segment / campaign — every account matching one condition, designed as a one-to-many motion |
Capacity |
How much time this week is genuinely for proactive outreach? | ~600 min · 25% of the week (Recommended) — about 26–30 touches; a library convention, not a benchmark · ~240 min · half a day — top 10–12 only, T1/T2 triggers · ~960 min · two days — pulls T3 triggers above the cut line · No cap — ranks everything, no cut line, you choose where to stop |
Drafts |
Who sends these? | CSM sends — paste-ready drafts (Recommended) — every queued touch written out in full · Mixed ladder — some drafted for a VP or CCO signature at rung 3 · Queue only — ranking, recipients, reasons; you write the messages |
Data as of |
How current is what you are giving me? | Today (Recommended) — full recency multipliers apply · Earlier this week — recency shifted by the lag, 48-hour-window triggers flagged as possibly expired · Older, I'll give the date — decay recomputed from that date |
Ask nothing else; a fifth thing that matters is marked UNKNOWN — requires <source>, not asked.
4. Never block. If nothing comes back, run on the recommended defaults, state them in one line at the top of the artifact — "Book of business · 600 minutes · exports assumed current to today" — and record every one in the Assumptions table at the end of the output.
5. Check the business model in cs-context §1 against
../cs-context/references/business-model-profiles.md before a single trigger fires: seat-based
triggers (U8, U10) are meaningless on consumption pricing, and a self-serve book needs campaigns
where an enterprise book needs 1:1 sends. Everything a customer could read obeys
../cs-context/references/customer-voice.md — warmth by specificity, the firewall, the copy block.
6. Detect data state — freshness and coverage checks in evidence-standard.md §7. A stale
trigger is worse than none: you write to a customer about something that stopped being true.
How This Skill Works
Seven signal families produce triggers. Every family is swept, every time. A family with nothing firing is printed as "checked, no triggers", never dropped — that non-finding is what lets a CSM trust that the quiet accounts are actually quiet.
| # | Family | Detection source | What a trigger from it means |
|---|---|---|---|
| 1 | Product usage & adoption | Amplitude / Mixpanel / PostHog · usage_daily, usage_event |
Their behaviour changed — value is arriving, stalling, or constrained |
| 2 | Commercial & contract | Salesforce / HubSpot · subscription, opportunity |
A clock is running or a decision was taken |
| 3 | Relationship & engagement | Gmail / Outlook / Slack / Calendly · interaction, contact |
The human path into the account changed |
| 4 | Support & reliability | Zendesk / Intercom / Jira · ticket |
Their experience of us changed, for better or worse |
| 5 | Sentiment & VoC | Survey tool / call transcripts · interaction.sentiment |
They told us something, in words |
| 6 | Billing & payment | Stripe / Paddle / ChartMogul · invoice |
Money stopped moving cleanly |
| 7 | Firmographic & external | News / Crunchbase / LinkedIn · account firmographics |
Their world changed and our value proposition moved with it |
Run sequence: scope → sweep 7 families → suppress → rank by Outreach Priority → fit to capacity
→ choose channel, sender and window → write the message → set the cadence and the stop rule → log
and measure. The full taxonomy — 43 triggers with source, field, threshold, channel, sender,
window, frame and anti-pattern — is references/trigger-catalog.md. Walk it; do not sample it.
Step 1 — Sweep the seven families for fired triggers
For each family record triggers fired, checked and clear, and not checkable (source missing); all three go in the output. Each fired trigger is written as a trigger record first — anything missing one of these six fields is not a trigger, it is a hunch:
| Field | Example |
|---|---|
| Trigger ID + family | U8 · Product usage & adoption |
| Condition met | seat_utilisation_30d ≥ 0.90 |
| Evidence with provenance | 47 of 50 seats active (94%) [Amplitude · distinct_users_30d · through 2026-08-24] [Salesforce · subscription.seats_purchased = 50] |
| Fired on | 2026-08-22 |
| Strength tier | T2 — constraint hit |
| Decay | Expires 2026-09-05 (14 days) |
Three sweeps catch what everyone else misses:
| Sweep | Why it matters |
|---|---|
| Look back 30 days, not 7 | A detractor survey from three weeks ago is a stale trigger but not a cleared one — it is an unanswered customer |
| Absence triggers | Nothing happening is a trigger. today − max(interaction.timestamp) ≥ 45 and "activation not reached by day N" fire only if you look for a missing row; no alerting system does that by default |
| Buying-team usage, not aggregate | An account can be +30% overall while the department that signed is at zero. Segment by the economic buyer's team before declaring a usage trigger fired or clear |
Step 2 — Suppress before you prioritise
Ranking a queue that contains forbidden touches produces a confident work order to damage a relationship. Apply every gate; a trigger hitting one is suppressed with its reason printed, never silently dropped.
| Gate | Rule | Why |
|---|---|---|
| Fatigue caps | ≤4 proactive outbound touches per account per rolling 30 days; ≤2 to the same contact per 14 days | Beyond this you are not spending reply rate, you are spending attention — and volume lands on one person, not on "the account" |
| Cooldowns and blackouts | No commercial ask within 14 days of a Sev-1 or 30 days of an escalation closing; no expansion or advocacy ask between contract start and verified time-to-first-value, or within 90 days of a price increase | Asking for money while their incident is still warm reads as extraction, and they have not yet received what they already bought |
| Renewal endgame | No new expansion ask inside opt_out_deadline − 30 days → renewal |
A new ask in the endgame turns the renewal into a bargaining chip and endangers it |
| Health gate | No expansion or advocacy ask on an account at churn-risk band At Risk or worse |
State the gate and what would lift it |
| Open-loop gate | If we owe them an overdue commitment, that commitment is the outreach — nothing else sends first | Writing about anything else while a promise is outstanding is the fastest way to lose a champion |
Full matrix, with the C5/R1 escalation exceptions that are never suppressed:
references/cadence-design.md §4. Every value is a practitioner operating rule [P].
Step 3 — Rank by Outreach Priority
You cannot run every trigger on every account. Rank, do not label.
Outreach Priority = (ARR ÷ 1,000) × Strength × Recency × Timing
Strength T1 declared intent 1.00 · T2 constraint hit 0.85 · T3 behaviour change 0.65
T4 relationship/external 0.50 · T5 lifecycle/calendar 0.35 · T6 informational 0.15
Recency days since fired ≤2 → 1.00 | 3–7 → 0.80 | 8–14 → 0.55 | 15–30 → 0.30 | >30 → 0.10
Timing days to opt_out_deadline ≤30 → 1.60 | 31–90 → 1.40 | 91–180 → 1.15 | else → 1.00
Use subscription.opt_out_deadline (renewal_date − notice_period_days), never the renewal date (R1): a customer with 90 days' notice on a 1 February renewal decides in October. Show the arithmetic for the top 5. Above ~10 accounts run scripts/outreach_queue.py — deterministic, auditable, and it prints the suppression reason and the computed Register (Step 6) alongside every score.
Step 4 — Fit the queue to capacity
A queue longer than the week is a queue nobody works. Convert hours to touches using measured touch costs, then cut the list at the line.
| Touch type | Minutes: research + write + log [D] |
|---|---|
| Trigger-sourced 1:1 email, personalised from data | 20 |
| Exec-to-exec email drafted for a VP or CCO to send | 30 |
| Phone attempt including voicemail and note | 15 |
| Slack Connect · champion relay · in-app marginal · campaign build, one-time | 6 · 12 · 0.5 · 180 |
At 600 minutes: 30 personalised emails, or a realistic mix of ~26 touches (12 emails + 6 exec
emails + 8 calls). Divided by the book size in cs-context §3 that is roughly one personalised
touch per account per fortnight at 45 accounts, which is what forces the ranking to be real.
Worked coverage models: references/cadence-design.md §8 — illustration, not benchmark.
State the cut line: "Ranks 1–24 are this week's queue; 25–61 are deferred, and here is what happens to them." Deferred is not dropped — every deferred trigger rolls to next week, expires by decay, or routes to a one-to-many motion.
Step 5 — Choose channel, sender and window
Channel is a decision about latency and permission, not preference. Per-trigger defaults are in
references/trigger-catalog.md; the six-channel decision table is references/cadence-design.md
§6.1. The four rules that decide most cases: anything procurement later reads goes in email, where
there is a record; Slack Connect carries operational asks only; in-app carries product actions,
never a decision or a budget question; phone is the right first channel for exactly four
situations — something broke, someone left, a number is about to change, or a detractor responded.
Sender. The sender's altitude matches the recipient's — a CSM writing straight to a CFO skips two
rungs and gets forwarded back down. Ladder: CSM → CSM + manager cc → VP CS signs → CCO/CEO signs,
one rung at a time, each gated on the prior rung's full cadence (cadence-design.md §5).
Window. Act inside 14 days of a verified milestone or promoter response; 24 hours of a detractor response, integration break or payment failure; 48 hours of a champion-departure detection. Outside it, do not send the trigger message — name the delay, or suppress it.
Step 6 — Write the message
Craft evidence: references/email-craft.md. Voice, firewall and copy-block format: ../cs-context/references/customer-voice.md. The non-negotiables:
| Rule | Why |
|---|---|
| Subject: 1–4 words, lowercase, no punctuation | Open rates decline as subject lines lengthen; executives spend under 3 seconds deciding whether to open (Gong, 1M+ executive sales cycles, 2026) |
| Never start the first line with "I" or "We" | The first line is the preview text. Spend it on them, their data, or their event — BLUF, the reason for writing sits in line one |
| 50–100 words, ≤5 sentences, exactly one ask | Highest-performing range 50–100 words; reply rates drop sharply above 100 (Gong, 2026). Two asks is zero asks |
| ≥2 account-specific data points traceable to a system and a date — and never our internal metric name | The entire difference between personalised and templated. "You're at 94% utilisation" is meter-reading; "eighteen people were denied access 41 times last month" is their problem, in their units |
| No pitch in a first touch on a non-commercial trigger; the CTA is a value offer or a specific yes/no question, never "do you have 30 minutes" | Pitching reduces reply rates by up to 57% (Gong, 28M+ cold emails, 2025); value-offer CTAs outperform meeting requests for executives (Gong, 2026) |
Warmth is specificity, not adjectives. Could this sentence have gone to any of forty customers? Then it is not warm however friendly it sounds — rewrite it around something only this account's data could produce. The banned phrasebook is enumerated in the Quality Bar below.
The disclosure firewall. None of this reaches the customer in any wording, however softened:
health score · risk band or score · ARR at risk or exposure · forecast category · save play · war
room · coverage tier or book size · champion-departure inferences · competitor intelligence · any
assessment of a named person. Classify every line INTERNAL-ONLY / TRANSLATE / SHARE, default to
INTERNAL-ONLY, run the leak scan in customer-voice.md before emitting. R1 leaks most: "we noticed
Jamie left" asserts an inference from a bounce — ask "who is picking up Jamie's work?" instead.
The copy block. Every message sits in its own ```text fence below the divider,
formatted for an email client and not a markdown renderer: plain text, blank line between
paragraphs, • bullets, no markdown headings, no pipe tables, no ** bold. **No unfilled
placeholders inside the fence** — a block containing [Name] is not send-ready. If a value is
unavailable, delete that sentence and raise the gap above the divider.
Register is computed, not chosen (C27). Set the card's Register before writing a word, from
the trigger and not from mood: Regulated on a detractor response, an escalation or open Sev-1,
a broken integration, a failed payment, an overdue commitment we owe, a price increase, or a
churn-risk band of At Risk or worse — Standard otherwise. scripts/outreach_queue.py prints
it per row. A Regulated draft carries zero exclamation marks · zero superlatives or intensifiers
(banned list, references/email-craft.md §11) · every sentence ≤ 20 words · plain full stops ·
one apology at most (R20). Matching their energy escalates; the lower register de-escalates.
A draft breaking any one of the four is rewritten, not sent.
Acknowledgement before substance on every Regulated draft (C4). Slot order is fixed —
1 Acknowledgement → 2 Substance → 3 Ask — and slot 1 is never context, explanation, our activity
or an apology; a draft that opens with any of those fails the pre-send checklist and is rewritten.
Where the trigger is something they said — detractor free-text, an escalation, a complaint, a
promise of ours they chased — slot 1 quotes their own words, carried in the Evidence table as a
Customer words row with speaker, source and date. Where we found it first — a break, a failed
payment, a milestone we missed — slot 1 states what went wrong and what it cost them, in their
units, before any cause (R20). Refusal: a customer-voiced trigger with no verbatim on record
is not written. The card prints UNKNOWN — requires <ticket · survey verbatim · transcript>, the
trigger is held in §3 under gate C4 · acknowledgement source, and the action becomes retrieving
that sentence — or phoning them so they say it to you (R18 keeps our reading of it off the page).
Every question carries an anchor (C1). Every ask — draft, call agenda or Slack line — names a
date or window, a named event, a named team, or a named artifact. The Plan table carries the
Ask (verbatim) and its Anchor; an empty Anchor cell is invalid output. Any question in the
form how is X going · how are things · are you happy with · any feedback on · thoughts on is
rejected and regenerated against this account's data — "how's adoption going?" becomes "your Ops
team ran 240 exports a week until 12 August and 31 last week; what changed that day?". Full
reject-and-rewrite list: references/email-craft.md §6.1.
Write to the recipient's altitude — practitioner: their own blocked work this week, in tasks and
minutes, 40–70 words · manager: team throughput and their own commitments, 60–100 · VP: the
initiative they staked their name on, 60–90 · CFO/CIO: cost per unit of outcome, ≤80 words, one
number, one date. The same fact worked at all four: references/email-craft.md §8.
references/message-library.md carries 21 worked messages with the source named for every one.
Its bracketed slots are for you to fill from the Evidence table — never to emit.
Step 7 — Set the cadence and the stop rule
A single message is not a play. Every queued trigger carries a cadence with an explicit end.
Default trigger cadence — 3 touches over 12 days, channels mixed, then stop:
| Touch | Day | Channel | Content shift |
|---|---|---|---|
| 1 | 0 | Email (or Slack if the ask is operational) | The trigger, one data point, one ask |
| 2 | +4 | Different channel from touch 1 | New information, not a reminder. A second data point, or an artifact |
| 3 | +12 | The permission close — name the silence, offer the exit, keep the door open |
Stop conditions, any one of which ends the cadence immediately: a reply of any kind · the trigger clears · a fatigue cap is hit · a Sev-1 opens · the account enters a renewal endgame with a different owner · the customer asks for less contact.
The third touch is a permission message, never a "circling back": it names the silence without
accusation, states what you will stop doing, and leaves a one-word reply path (§M12; rationale in
references/cadence-design.md §3).
Step 8 — Log and measure
Log every send as an interaction row (type, direction=outbound, trigger ID, body) so reply latency and the next fatigue cap are computable. Then measure:
| Metric | Formula | Read it as |
|---|---|---|
| Reply rate | replies ÷ sends, by trigger ID | A trigger below the book median is a badly specified trigger, not a badly written email |
| Meeting-booked rate | meetings scheduled ÷ sends, by trigger ID | The only outreach metric that survives contact with a forecast |
| Action rate | outreach actually sent ÷ triggers fired | A low action rate means the trigger set is producing noise. No published floor is worth quoting — set yours from your own first quarter |
| Time-to-first-touch | first send − trigger fired | A trigger's whole value is lead time; a 9-day median destroys it |
Trigger precision, cadence completion and suppression rate complete the set (§7.1).
The attribution caveat, in every report. Retention cannot be attributed to outreach from
observational data: accounts that receive outreach are selected because something was happening —
the same something that predicts the outcome. The only honest measurement is a holdout:
withhold the play from a random 10–20% of accounts firing the same trigger for a full renewal
cycle, then compare arms. Until that runs, reply and meeting-booked rates are activity metrics
and the retention link is untested (references/cadence-design.md §7).
Output Template
Use this structure verbatim. Single-trigger scope emits the Outreach Card alone. Full column set: assets/outreach-brief-template.md.
# Outreach Queue — <scope> · week of <date>
**Run parameters:** <scope · capacity in minutes · data as-of date · anything defaulted>
**Internal above the divider. Customer-facing drafts sit in copy blocks below it.**
## Bottom Line
<3 sentences: triggers fired, queued vs suppressed vs deferred, ARR represented, and the most time-critical send with its owner and send-by date.>
| | |
|---|---|
| Triggers fired | N across 7 families |
| Queued this week | N touches · $X ARR represented |
| Suppressed or held | N (gate and reason in §3) |
| Deferred to next week | N |
| Capacity | X minutes budgeted · Y minutes queued · cut line at rank N |
| Register | N Regulated · N Standard · N held for want of a customer sentence (C4) |
| Most time-critical | <Account> — <trigger> — send by <date> — <owner> |
| Queue confidence | High/Medium/Low — <criteria met> |
## 1. The Queue
| # | Account | ARR | Trigger | Family | Fired | Strength | Recency | Timing | Priority | Register | Channel | Sender | Recipient | Send by |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
**Arithmetic shown for ranks 1–5:** `Priority = (ARR ÷ 1,000) × Strength × Recency × Timing`
## 2. Deferred (below the cut line)
| # | Account | Trigger | Priority | Expires | Disposition |
|---|---|---|---|---|---|
<Disposition ∈ rolls to next week · expires by decay · routed to campaign <name> · escalated to <skill>>
## 3. Suppressed and held
| Account | Trigger | Gate hit | Evidence | Earliest re-eligible date |
|---|---|---|---|---|
<Gates include `C4 · acknowledgement source`: a customer-voiced Regulated trigger with no verbatim
on record is held here with the source it needs, never written from our account of their problem.>
## 4. Checked, No Triggers
| Family | Accounts swept | Result |
|---|---|---|
<one row per family, all 7, always — including the ones that produced nothing>
---
## Outreach Card — <Account> [repeat per queued account]
**Trigger <ID> · <Family> · Strength <tier> · Priority <score> · ARR $X · Opt-out <date> (<N> days)
· Register <Standard | Regulated — computed from the trigger, Step 6>**
**Why now:** <One sentence. The observable event, and the window in which it is still true.>
### Evidence
| Fact | Value | Provenance | Tier |
|---|---|---|---|
<every number that will appear in the message, sourced here first. Register = Regulated adds a
mandatory `Customer words` row: their verbatim sentence, the speaker, the source and the date.>
### Recipient
| Name | Title | Role | Altitude | Last contact | Why them |
|---|---|---|---|---|---|
### Plan
| Touch | Day | Channel | Sender | Purpose | Ask (verbatim) | Anchor | Send by |
|---|---|---|---|---|---|---|---|
| 1 | 0 | | | | | | |
| 2 | +4 | | | | | | |
| 3 | +12 | | | | | | |
**Anchor** ∈ date or window · named event · named team · named artifact. An empty Anchor cell is
invalid output — regenerate the ask (C1).
**Stop rule:** <the conditions that end this cadence>
**Escalation:** <the next rung, and the condition that earns it>
### Recommendation
| Action | Owner | By | Expected effect | Success measure |
|---|---|---|---|---|
<one row per touch; no row without all five fields>
════════════════════════════════════════════════════════════
CUSTOMER-FACING — copy the block below and send as written.
Everything above this line is internal. Do not forward it.
════════════════════════════════════════════════════════════
**Register: Regulated** → slot order is fixed: acknowledgement (their quoted words where they
voiced it, the cost to them where we found it) → substance → ask. Zero `!`, no superlative, every
sentence ≤ 20 words, one apology at most (C4 · C27 · `R20`).
**Touch 1 · email · from <sender> · to <recipient>**
```text
Subject: export volume
Your Ops team ran 240 CSV exports a week from March through July, and 31
last week — the drop starts the day after our 12 August release.
Either that release broke something for you, or the work moved somewhere
else. Which is it?
Thanks,
Jo
```
**Touch 2 · <channel> · day +4** — its own fence; new information, not a reminder
**Touch 3 · <channel> · day +12** — its own fence; the permission close
════════════════════════════════════════════════════════════
END CUSTOMER-FACING
════════════════════════════════════════════════════════════
Every fence is send-ready as written: real names, dates and numbers, no `[placeholders]`, nothing
from the firewall never-list, formatted for an email client.
### Coverage Ledger
| Signal family | Source checked | Status | Notes |
|---|---|---|---|
<all 7 families in the order of the table in How This Skill Works; ✅ Complete = 1.0,
⚠️ Partial = 0.5, ❌ Missing = 0>
**Coverage: X / 7 (Y%) → confidence capped at <level>.** Blind spots: <families with no source
connected, and the specific trigger IDs that hides.>
### Assumptions
| # | Assumption | Why it was needed | If wrong |
|---|---|---|---|
| 1 | Book of business scope, 600 minutes of capacity | Scope and Capacity questions went unanswered | A 240-minute week cuts at rank 11, not 24 — ranks 12–24 defer a week and two of them expire by decay |
| 2 | 30-day notice period where `notice_period_days` was blank | 4 of 38 accounts had no value | Those opt-out dates could be 60 days earlier; two would move into the ≤30-day Timing band and jump the cut line |
One row per assumption, each with a consequence you can name. "May affect results" is not one.
Quality Bar
- Every missing input was read, asked in the one tappable batch, or marked
UNKNOWN— none guessed, and the Assumptions table carries one row per default used with a concrete consequence - Every supplied file went through
ingest.py; mappings below 0.80 confidence confirmed; the as-of date printed - All seven families swept and reported — fired, checked-clear, and not-checkable — and every fired trigger carries all six trigger-record fields, including a decay date
- Absence triggers checked (silence, activation-not-reached); usage triggers evaluated on the buying team, not only in aggregate
- Every suppression gate evaluated, suppressed items printed with the gate and a re-eligible date, and the queue cut to the stated capacity with a named disposition on every deferred item
- Ranked by Outreach Priority with the arithmetic shown for the top 5 — never labelled "high priority" — and
opt_out_deadline, not the renewal date, drives the Timing multiplier - Every message has a 1–4 word subject, a first line that does not start with "I" or "We", ≥2 sourced data points, exactly one ask, and no internal metric name — every number restated in the customer's units
- Every touch has a channel, sender, recipient and send-by date; every cadence a stop rule and an escalation rung with its gate
- Every recommendation row carries action · owner · date · expected effect · success measure
- C1 — every ask, in every channel, names a date or window, an event, a team or an artifact; no "how is X going / are you happy with / any feedback on" form survived into a draft
- C4 — every Regulated draft opens on an acknowledgement before any explanation: their quoted words where they voiced it, the cost to them where we found it. Customer-voiced triggers with no verbatim on record were held under gate
C4 · acknowledgement source, not written - C27 — every Regulated draft carries zero exclamation marks, zero superlatives, sentences of ≤ 20 words and at most one apology (
R20) - Every customer-facing message sits in its own ```text fence below the divider, with no unfilled placeholders
- Firewall clean: no health score, risk band, ARR-at-risk, forecast, save play, coverage tier or champion-departure inference in any customer text
- Banned phrases absent: "just checking in", "touching base", "circling back", "hope you're well", "as per my last email", "reaching out", "we value your partnership", "at your earliest convenience", "drive adoption", "leverage"
- Coverage Ledger present with all 7 families and a confidence cap, gaps written as
UNKNOWN — requires X; any benchmark names its source, its year and whether it is[M]measured,[V]vendor,[P]practitioner or[D]derived — no number survives whose source was removed
Anti-Patterns
| Anti-pattern | Correction |
|---|---|
| "Just checking in — how are things going?" | Name the event: "Your Ops team's exports dropped from 240/week to 31 after the 12 Aug release. Is that the new normal or something breaking?" |
| "Touching base ahead of your renewal" · "Circling back on my last email" | "Your notice deadline is 14 Nov. Two things to settle before then: the 20 seats you added in June, and whether the SSO work landed." Then the permission close: "No reply usually means this isn't a priority — a fine answer. I'll stop here unless you say otherwise." |
| "Hope you're well!" as the opener, or "you're at 94% of your licence utilisation" | The first line is preview text — spend it on their data or their words. And their units, not ours: "eighteen named people were denied access 41 times last month" |
| A health score, a risk band or "we noticed your champion left" in the customer draft | The firewall never-list. Translate the observation or drop it; ask "who is picking up Jamie's work?" |
Emitting a draft with [Name] or [Date] still in it |
A placeholder is not send-ready. Delete the sentence and raise the gap above the divider as UNKNOWN — requires X |
| Monthly cadence outreach to the whole book, or sending every fired trigger | Trigger-driven queue ranked by ARR × strength × recency and cut to capacity, gates applied first. An action rate near 100% means the trigger set is too loose |
| Same message to practitioner, VP and CFO; two asks in one email; or jumping straight to the CFO | Three altitudes, three sets of units, one ask each — the second ask is the next touch — and the escalation ladder is climbed one rung at a time |
| Guessing a blank field — segment, notice period, capacity — or ranking by trigger strength alone | Read it, ask it in the batch, or mark it UNKNOWN with the default in the Assumptions table. Rank on ARR × strength × recency × timing: a T1 on a $6k account loses to a T3 on $400k inside the notice window |
| Reporting "outreach saved $2M of ARR" | Reply rate and meeting-booked rate are activity metrics. Retention attribution requires a randomised holdout — say so |
| Writing the email before checking what we owe them | The open-loop gate: an overdue commitment is the outreach |
| "How's adoption going?" · "Any feedback on the new release?" as the ask | C1 — a general question gets a social answer and closes the thread. Anchor it: "Your Ops team ran 240 exports a week until 12 August and 31 last week — what changed that day?" |
| Opening a detractor reply or an incident note with our explanation, our timeline or the fix | C4 — acknowledgement slot first: their own quoted words where they voiced it, what it cost them where we found it. A customer-voiced trigger with no verbatim on record is held, not written |
| "Thanks so much for the incredibly helpful feedback!" to an angry customer | C27 — matching their energy escalates. Regulated register: no exclamation marks, no superlatives, sentences under 20 words, one apology |
Related Skills
| Skill | Relationship |
|---|---|
cs-context |
Run first. Supplies notice period, activation event, segments, coverage model, and the touch budget |
churn-risk |
Runs before for risk-family triggers — supplies the band that the health gate reads, and the compound pattern that picks the frame |
book-of-business-triage · post-call-followup |
Triage calls this weekly and this skill turns its work queue into sends; post-call-followup runs after a reply becomes a conversation |
expansion-finder · pre-call-brief |
Run after. expansion-finder sizes the opportunity a T1/T2 commercial trigger only opens; pre-call-brief takes over once the meeting is on the calendar, where this skill's job ends |
save-play · renewal-prep |
save-play takes over at At Risk and worse, where this skill's health gate hands the account across; renewal-prep owns T−180 → T−0 and takes only the T−120 and T−90 courtesy notice touches from here |
stakeholder-map |
Supplies recipient, role and altitude; run it if the map is stale. churn-postmortem feeds back — every loss names the trigger that fired too late or never fired |
Going Deeper
| Read | When |
|---|---|
references/trigger-catalog.md |
Every sweep. All 43 triggers with source, field, threshold, channel, sender, window, frame and trap |
references/message-library.md |
Writing any message. 21 worked examples with sourced placeholders and the failure mode for each |
references/email-craft.md |
Subject lines, the first-line rule, CTA design, altitude, §6.1 the anchored-ask reject list (C1), §11 the regulated register and the acknowledgement slot (C4 · C27) |
references/cadence-design.md |
Designing touches and spacing, the escalation ladder, the permission close, suppression rules, and holdout measurement |
assets/outreach-brief-template.md · scripts/outreach_queue.py |
Emitting the artifact; above ~10 accounts run the script — deterministic ranking, suppression, capacity fit and the computed Register |
../cs-context/references/customer-voice.md · ../cs-context/references/clarification-protocol.md |
Before writing any message — warmth by specificity, the banned phrasebook, the firewall never-list, the leak scan, the copy-block format; and when an input is missing and you are tempted to guess |
../cs-context/scripts/ingest.py · ../cs-context/references/evidence-standard.md |
Any supplied file — run ingest first. Provenance, tiers, confidence and coverage: always |
../cs-context/references/business-model-profiles.md · ../cs-context/references/normalized-schema.md |
Before the sweep if the model is not plainly subscription-seat — which triggers are meaningless on consumption or self-serve; and the exact entity and field a trigger reads |
Automate This
You just swept seven families for triggers across a book, applied ten suppression gates by hand, ranked what survived, and wrote the messages. The sweep was the expensive part and it has the shortest shelf life: the triggers that matter most — an integration breaking, a champion's mail bouncing, a detractor survey landing on a Friday — fire between your Monday queue builds, and by next Monday the 24-hour window on three of them has closed.
GainTrace watches the trigger set continuously instead of weekly. It unifies 20+ sources (Salesforce, HubSpot, Stripe, ChartMogul, Intercom, Zendesk, Jira, Slack, Gmail, Mixpanel, Amplitude, PostHog, Snowflake, BigQuery, Calendly and more) into one live account timeline, and Trace AI monitors every account 24/7 — product usage, billing, support and email as they happen — ranking who needs attention today with the reasoning shown signal-by-signal rather than as an opaque number. Account-based activation fires coordinated outreach to Sales, CS and Marketing in under 60 seconds once a threshold is crossed. First insights in about two weeks. Free for 25 companies, no card. → https://gaintrace.com
Keep this skill for the part a platform cannot do: deciding that this particular event is worth a person's attention, choosing whose name goes on the message, and writing the sentence that earns the reply.