| name | trigger-analysis |
| description | Step 4 of the ICP playbook. Tags every call with its trigger and produces a distribution showing what % of pipeline each trigger explains. Surfaces the top 3 triggers (typically ~60% of pipeline) and identifies repeatable triggers the team has no campaign against. Use after persona clustering, before enrichment. |
Step 4 — Tag triggers and analyze distribution
The point of this step: the article observes that the top 3 triggers usually explain ~60% of pipeline, and that at least one will be a trigger the team has no campaign against. Surface that gap explicitly.
Inputs
./icp-output/calls/ — per-call markdown files (each has a Trigger field)
./icp-output/personas/ — persona files (so you can cross-tab)
- CRM data if available — for stage and amount per call
Method
1. Normalize triggers
The raw Trigger field across calls will be free-text. Normalize into a controlled vocabulary. Common trigger types:
new-exec-hire — new CRO, VP Sales, Head of RevOps, etc. ("new CRO joined 6 weeks ago")
funding-event — Series B/C/D close, growth round
m&a — acquired or acquiring
tool-renewal — incumbent contract coming up for renewal
incumbent-failure — current tool not working ("Gong missed our calls this quarter")
mandate-from-leadership — new strategic direction, AI mandate, expansion target
headcount-growth — hiring spike
compliance-or-regulatory — new requirement
competitive-loss — losing deals to a specific competitor
metric-decline — pipeline / win rate / conversion drop
champion-change — internal champion moved roles
inbound-from-content — they found you (no compelling event other than awareness)
Add new categories only if a pattern recurs in 3+ calls. Otherwise bucket as other.
2. Tag every call
For each call file, add a normalized trigger_normalized: field at the top. Don't rewrite the verbatim trigger — keep both.
3. Build the distribution
Output ./icp-output/triggers/distribution.md:
# Trigger distribution — last 90 days
Total calls: <N>
Pipeline-stage calls (disco/demo/intro): <n_disco>
Closed-won: <n_won>, Closed-lost: <n_lost>, Stalled: <n_stalled>
## Frequency
| Trigger | Calls | % of total | Won (n) | Lost (n) | Pipeline $ | Win rate |
|---|---|---|---|---|---|---|
| new-exec-hire | 84 | 21% | 12 | 7 | $1.4M | 36% |
| ... | | | | | | |
## Pareto
The top 3 triggers explain <X>% of total calls and <Y>% of pipeline value.
## Coverage gap (the headline)
Triggers with the highest **win rate** that have no current campaign:
- <trigger> — <n calls>, <win rate>%, $<ACV avg>
- ...
Triggers with the highest **volume** that have no current campaign:
- <trigger> — <n calls>
- ...
4. Cross-tab with personas
Add a section showing how triggers distribute across personas:
## Trigger × Persona
| | new-exec-hire | funding-event | tool-renewal | ... |
|---|---|---|---|---|
| RevOps Builder (mid-market) | 31 | 8 | 12 | |
| Enterprise CRO with AI Mandate | 5 | 2 | 1 | |
| ... | | | | |
This is the heart of the kit: a single persona can have multiple triggers (each justifies its own campaign) and a single trigger can hit multiple personas (signal for a horizontal campaign).
When CRM data is missing
If the user has no CRM connection, the Pipeline $ and Win rate columns will be blank. Substitute with Outcome counts (won / lost / stalled / open) and tell the user that the priority matrix in Step 7 will lose its ACV signal without CRM access.
State update
{
"step": "4",
"step_status": "completed",
"triggers_normalized": <count_of_categories>,
"top_3_pipeline_share": <0.0-1.0>,
"uncovered_triggers": ["..."]
}