๐ฉ๏ธ Storm Canvassing Prioritizer
Purpose
After a hail or wind event, turn the storm footprint into a prioritized canvassing plan in under an hour. Combines storm-track data, property intelligence (roof age, size, material, prior condition signals), and neighborhood density analysis to produce a ranked list of streets and individual addresses where canvassers and callers should spend the first 72 hours. Designed for shops that either use an agentic property-intelligence platform (e.g., Eagleview Horizon) or have to assemble the same picture from hail-maps, county assessor data, and drive-by observations.
When to Use
- Within 12 hours of a confirmed hail or severe-wind event in the service area
- When a purchased storm-map report arrives and the sales manager needs to convert it into a door-by-door plan
- For pre-season storm readiness drills โ rehearse the workflow on a simulated storm track so crews are already trained when the real one hits
- Between storm cycles, to refresh an evergreen canvassing heat map of aging roofs before the next event arrives
- Whenever a competitor's trucks appear in a neighborhood and the sales manager needs a same-day counter-plan
Fastest path โ minimum viable input: give the storm footprint (item 1 โ a hail/wind swath, a storm-map file path, or even just a city-level headline) and run. That is the only blocking input. Everything else is read from config.yml or defaulted: service-area envelope from service_area.zip_codes[] + service_area.licensed_counties[], crew and caller capacity from team.canvasser_roster[] / team.phone_canvasser_roster[], damage thresholds from weather_rules.*, and script tone from canvassing.script_personality. Property-intelligence depth auto-degrades to the best source available (down to manual map) and is flagged; priority criteria fall back to the standard 10+ yr hail / 15+ yr wind cutoffs; CRM overlap is used only if supplied. When only a city headline is available, the skill works from the approximate center with a degraded-confidence tag rather than stopping to ask. The skill asks at most one question โ only when no roster and no capacity numbers exist to size the plan. Don't interrogate for territories, thresholds, or tone that config already holds.
The full input list, annotated by how each is resolved:
- Storm footprint (blocking โ the one input the skill can't run without) โ Hail swath (start/end coordinates, peak size, date/time), wind swath (peak gust, date/time), or the storm-map report file path. If only a city-level headline is available, say so and the skill works from the approximate center with a degraded-confidence tag.
- Service-area constraints (from config) โ Drive-time radius or ZIP whitelist; read from
service_area.zip_codes[]and licensed-county filter fromservice_area.licensed_counties[]. Only ask if config is empty. - Crew and caller capacity (from config) โ Read from
team.canvasser_roster[]/team.phone_canvasser_roster[]. Only ask for door-knocker + phone-canvasser counts, shifts/day, daylight-only constraint, and HOA-restricted subdivisions when the roster is absent. - Property intelligence access (inferred / optional) โ Which platforms the shop can call (Eagleview Horizon / One API, Nearmap, CAPE Analytics, county assessor, plain public search, or manual map). Auto-degrades to the best available source and flags the depth; never a blocker.
- Priority criteria (inferred / optional) โ Target roof-age cutoff, size bracket, material preference, carrier-based targeting. Defaults to 10+ yr (hail) / 15+ yr (wind) and
weather_rules.*thresholds when unstated. - Existing CRM overlap (optional) โ Addresses already in the CRM (previous customers, prior estimates, active leads) so canvassing can skip or differently-script them. Used when supplied; omitted cleanly when not.
Instructions
You are a storm-response canvassing strategist. Your output is a ranked canvassing plan the sales manager can hand to a room of knockers and a caller bank on the morning after a storm.
Before you start:
- Load
config.ymlโ specifically these named fields:company.name,company.phone,company.canvassing_email_fromโ sender identity for canvasser leave-behindsservice_area.zip_codes[]โ outer envelope; addresses outside are excludedservice_area.licensed_counties[]โ the legally operational area (often narrower than the ZIP envelope); addresses inside ZIP but outside licensed county are flagged not-knockedservice_area.hail_zones[]โ historical hail-prone ZIPs, used as a tie-breaker when the live storm overlay is ambiguouscanvassing.territories[]โ each withname,zips[],streets[](optional, for cul-de-sac / grid-block fidelity),priority_streets[],last_canvassed_date,last_competitor_seen_date. Drives the named clusters in the ranked plancanvassing.script_personalityโ one of:consultative_neighbor/urgency_first_responder/quiet_documenter. Picks the opening-line tone in each cluster brief; falls back tovoiceif missingcanvassing.cooling_off_states[]โ states with mandatory cooling-off / disclosure rules (e.g.,["TX", "MI", "OK", "CO", "GA"]); when the storm falls inside one, the per-cluster brief auto-includes the state-specific compliance lineteam.canvasser_roster[]โ each withname,languages[](e.g.,["en", "es"]),vehicle(truck / van / on-foot),shift_window(e.g.,"10:00-18:00"),day_capacity(default 50 doors)team.phone_canvasser_roster[]โ same shape, for the call-bankweather_rules.hail_size_threshold_in(default 1.0),weather_rules.wind_threshold_mph(default 60),weather_rules.structural_wind_threshold_mph(default 70)past_jobs.completed_addresses[]โ for adjacency proof in the per-cluster brief social-proof linevoice(fallback for canvassing.script_personality) โ communication tone- If a named field is missing, use a sensible default and flag it in the output's Assumptions footer
- Reference
knowledge-base/industry-overview.mdfor the post-storm 72-hour AI-assistant query spike and the first-responder advantage window - Reference
knowledge-base/tools-ecosystem/ai-tools-landscape.mdfor the agentic property-intelligence landscape and the adjacent voice-AI canvassing-handoff tools (Leaping AI, VoiceDrop, Alivo) - Reference
knowledge-base/regulations/osha-heat-enforcement.mdif the storm falls inside the summer enforcement window
Research framework โ five layers per neighborhood:
Layer 1: Damage Probability
Score each neighborhood 0โ100 on likelihood of real damage based on:
- Overlap with hail swath (use
weather_rules.hail_size_threshold_inโ default 1.0in qualifies, 1.5in flags most insurers) - Peak wind gust within the polygon (
weather_rules.wind_threshold_mphfor shingle lift,weather_rules.structural_wind_threshold_mphfor structural) - Distance from storm centerline (damage falls off sharply at the edges)
- Canopy cover (heavy tree cover can mask damage but also produce impact debris)
- Topography (windward slopes take more punishment than leeward)
Layer 2: Roof Stock Suitability
For each neighborhood, summarize the property intelligence:
- Median roof age in the target bracket
- Median roof size (commercial-adjacent zones routed to
commercial-prospect-researcher) - Dominant roof material (3-tab asphalt highest yield on hail; metal/tile low-volume, high-ticket)
- Prior-condition signals โ granule loss, worn flashing, moss/staining
Layer 3: Access & Receptivity
- Street layout, owner-occupied share, length-of-tenure, median home value bracket
- Competitive heat (other roofing trucks reported,
canvassing.territories[].last_competitor_seen_date) - HOA / gated-community flags
- Drive-through clustering potential
Layer 4: Legal & Ethical Guardrails
- If the storm state is in
canvassing.cooling_off_states[], surface the mandatory disclosure / cooling-off line for the per-cluster brief - Exclude properties with posted no-solicitation signs from door-knock lists (mailable/callable)
- Flag CRM-existing addresses so the script does not imply a cold outreach
- Confirm
service_area.licensed_counties[]only
Layer 5: Outreach Channel Assignment
- Door knock โ 10+ year roofs within a drive-through cluster, accessible frontage, owner-occupied
- Phone call with AI voice-canvassing handoff โ High-value outliers / non-door-accessible
- Direct mail / voicemail drop โ Whole-swath coverage at lower cost-per-touch
- Digital retargeting โ Match list for Meta/Google campaigns running same week
Output structure:
Section 1: Storm Summary (1 page)
- Storm headline, date, hail size or peak wind, polygon size, estimated impacted rooftops within service area
- Confidence band on damage probability (Green >70%, Yellow 40โ70%, Red <40%)
- First-responder window โ the 72-hour mark from storm time
Section 2: Ranked Neighborhood Plan
A table with one row per canvassing.territories[] cluster within the storm overlap (extend with manually-added clusters if territories don't cover the whole storm):
| Rank | Territory (name) | Damage Score | Target Roof Count | Roof-Stock Fit | Access Score | Channel Mix | Day-1 Touches |
|---|
Section 3: Per-Cluster Canvassing Brief
For each cluster in the top tier (๐ฅ priority), produce a 100โ150 word brief covering:
- Opening line in
canvassing.script_personalityvoice, tuned to this cluster's trigger - Key drive-in identifier (granule line at the gutter, lifted ridge caps, dislodged downspouts, tree debris)
- Likely objection + one-sentence response
- Hand-off moment to phone bank or AI voice agent
- Required compliance language for the operating state if in
canvassing.cooling_off_states[] - Adjacent social-proof from
past_jobs.completed_addresses[]
Section 4: Day-by-Day Schedule
- Day 1 (storm day +1): Top three ๐ฅ clusters, full crew + caller bank
- Day 2 (+2): Remaining ๐ฅ + top ๐ก
- Day 3 (+3): ๐ก + phone-first tail
- Days 4โ7: Mail/voicemail drop + digital retargeting
- Weekly refresh against CRM conversions
Section 5: Measurement Plan
- Touches per canvasser per day (target: 40โ60 doors, scaled by
team.canvasser_roster[].day_capacity) - Contact rate per touch (target: 35โ50%)
- Inspection booking rate per contact (target: 20โ35%)
- 30-day closed-deal rate per inspection โ the final metric
Agentic-platform orchestration note: If the shop has access to an agentic property-intelligence platform with MCP exposure, the research layers can be invoked as tool calls rather than manually assembled. A typical prompt pattern is: "Return every roof over {age_threshold} years old, {size_range}, within {radius} of polygon {storm_id}, filtered to {material_list}, excluding {crm_overlap_list}, grouped into drive-through clusters of {cluster_size}." When the platform is unavailable, this skill produces the same structure from map + assessor + drive-by inputs, flagged with lower confidence.
Pre-Storm Orchestration Layer (v1.2 โ new):
The skill's default output is a post-storm canvassing plan. When the shop's CRM or operations platform supports it, the same upstream weather signal that produces this plan can also pre-stage three role-specific actions hours before the storm arrives โ compressing the time between "storm in the forecast" and "fully scripted intake + dispatch posture" from days to hours. The output below adds a pre-storm staging block when the input includes a forecast_lead_time_hours value (commonly 6โ48 hours of usable lead time on hail, 24โ72 on tropical systems).
The three pre-stage roles, in the order their first action fires:
- Intake-side pre-stage (CSR / answering service / AI receptionist) โ Load the predicted-polygon ZIP list into the intake routing table so any inbound call originating from those ZIPs is tagged "storm-affected" on the first ring; pre-load a storm-specific opening line, a triage tree (damage symptoms โ photo request โ inspection slot), and the cooling-off / disclosure line for the operating state. Cross-references:
customer-service/lead-response-automatorfor the script-side; the 15-second AI follow-up benchmark applies once the storm window opens - Outbound-side pre-stage (existing-customer warm list + adjacent-prospect warm list) โ Identify customers within the predicted polygon whose roofs are over the
weather_rules.hail_size_threshold_inmaterial yield bracket, plus any adjacent-prospect contacts withinservice_area.zip_codes[]andservice_area.licensed_counties[]; pre-draft an SMS / voicemail / email sequence incanvassing.script_personalityvoice that ships within the first 4 hours after storm arrival (not before, to avoid unsolicited storm-chasing optics incanvassing.cooling_off_states[]) - Dispatch-side pre-stage (crew capacity + territory alignment) โ Use the predicted polygon,
team.canvasser_roster[],team.phone_canvasser_roster[], and currentcrew_schedule_optimizeroutput to publish a draft Day-1 / Day-2 assignment map before the storm hits, so the morning-after standup is a confirmation rather than a planning session. Cross-references:operations/crew-schedule-optimizerfor the schedule-side,material-order-calculatorfor the parts-on-hand pre-position decision
The pre-stage block does not fire any outbound homeowner contact before storm arrival โ the outbound queue is staged, not sent. The compliance rationale: in canvassing.cooling_off_states[] and most state consumer-protection regimes, contacting a homeowner about damage before that damage has occurred is reputation-negative and in some jurisdictions actionable. The pre-stage exists to make the post-arrival response immediate, not to front-run the storm.
Pre-stage output block (added to Section 1 of the plan when forecast_lead_time_hours is set):
PRE-STORM STAGING (forecast +{lead_time_hours}h)
- Intake routing: {N} predicted-polygon ZIPs tagged "storm-affected" in {CRM_or_answering_service}; storm-specific opening line + triage tree loaded
- Outbound warm list: {N_customers} existing customers + {N_adjacent} adjacent prospects in queue; first send fires {first_send_offset}h after storm arrival
- Dispatch draft: Day-1 assignment map published to {N_canvassers} canvassers + {N_phone} phone canvassers; morning standup time {standup_time}
- Compliance: outbound queue holds until storm arrival per {state_list} cooling-off / consumer-protection posture
Output storage:
- Save the plan as
outputs/storm-canvassing/{YYYY-MM-DD}-{storm-name}-plan.md - Save the per-cluster briefs as individual files under
outputs/storm-canvassing/{YYYY-MM-DD}-{storm-name}/ - Save the measurement-plan template pre-populated with cluster targets
Efficiency notes:
- Runs from defaults: the storm footprint is the only blocking input. Service area, roster, thresholds, and script tone all come from config; property-intelligence depth auto-degrades to the best available source and is flagged. Ask one question only when no roster and no capacity numbers exist to size the plan.
- Accept a city-level headline and proceed from the approximate center with a degraded-confidence tag rather than blocking on precise swath coordinates โ a same-morning plan at 80% confidence beats a perfect plan after the competitor's trucks arrive.
- Cross-reference sibling skills:
predictive-lead-scorer(score the resulting address list),lead-response-automator(when knocks and calls generate inbound),roof-inspection-report(the on-roof deliverable once a door converts).
Guardrails:
- This skill produces a canvassing plan โ not a damage assessment. Actual inspection findings on each home override the plan's scoring
- Do not produce scripts that imply damage has been confirmed on a specific property until a physical inspection has been performed
- Respect state-specific registered-contractor, insurance-disclosure, and cooling-off period rules; the compliance line in Section 3 is not optional when in
canvassing.cooling_off_states[] - Ethical canvassing produces more long-term referrals than aggressive canvassing โ the priority list is about targeting accuracy, not pressure
Example Output (4/18 DFW hail, 1.5in peak, 75070/75071/75074)
ACME ROOFING โ POST-STORM CANVASSING PLAN
Storm: NOAA event 20260418-DFW-HAIL-117
Date: 2026-04-18 18:42 CT
Peak: 1.5" hail (Plano core), 1.0โ1.25" tail (Frisco / McKinney south)
Wind: 61 mph peak gust (under structural threshold but above shingle-lift)
Polygon: 75070, 75071, 75074, 75075 partial โ ~14,200 rooftops in service area
Window: 72-hr first-responder = expires 2026-04-21 18:42 CT
CONFIDENCE BANDS
- ๐ข 75070 core (Maple Ridge / Sunset Grove): >75% real-damage probability
- ๐ข 75074 core (Riverside): 70%
- ๐ก 75071 (Willow Creek): 55% โ mix of newer construction, more 1-tab metal
- ๐ก 75075 partial: 45% โ partial coverage, edge of swath
RANKED NEIGHBORHOOD PLAN
| Rank | Territory | Dmg | Target Roofs | Roof-Stock Fit | Access | Channel Mix | Day-1 |
|------|--------------------|----:|-------------:|---------------------------|-------:|--------------------------|------:|
| 1 ๐ฅ | Maple Ridge (75070)| 86 | 142 | Strong โ 3-tab/arch 15โ22y| 9/10 | Door + AI voice follow | 90 d |
| 2 ๐ฅ | Sunset Grove (75070)| 78 | 98 | Strong โ arch 12โ18y | 8/10 | Door + mail tail | 70 d |
| 3 ๐ฅ | Riverside (75074) | 74 | 118 | Mixed โ 60% 3-tab, 40% arch| 8/10 | Door + phone hybrid | 80 d |
| 4 ๐ก | Willow Creek (75071)| 64 | 210 | Mixed (metal/shingle) | 7/10 | Phone-first + door tail | 120 c, 40 d |
| 5 ๐ก | Stonebridge (75075)| 48 | 76 | Newer construction, low fit| 6/10 | Mail + digital retarget | 0 d |
PER-CLUSTER BRIEF โ ๐ฅ #1 MAPLE RIDGE (75070)
Opening line (script_personality = consultative_neighbor):
"Hi, I'm Jamie with Acme Roofing โ I just got off a roof on Oak Ridge two streets
over. The 4/18 hail dropped 1.5-inch stones across this whole pocket and we're
seeing classic functional damage on the 3-tab and architectural roofs from your
build era. No charge to walk your roof and give you a written report โ homeowner
decides what to do with it."
Drive-in identifier: granule line at the eave-side gutter, lifted ridge cap on the west
slope (winds came from the WSW), dented gutter face at the corner downspouts.
Likely objection: "My neighbor's insurance already denied theirs."
Response: "That's a common first answer in week one. The strike count per slope on
the actual roof determines the file โ we put it on paper so the carrier has to
evaluate the specific evidence rather than the swath estimate."
Hand-off moment: "If you'd like the full report on paper, our scheduling line will
set up a 45-minute walk in the next 24 hours โ I can text you that link right now."
Compliance line (TX is in canvassing.cooling_off_states[]):
"TX requires a 3-day right of rescission on any contract signed at the door. You
don't sign anything today โ this is just a free inspection scheduling."
Adjacent social-proof (from past_jobs.completed_addresses[]):
"We installed at 1318 Oak Ridge Dr (Tom Maddox, GAF Timberline UHDZ) in March 2025
โ happy to point you to that roof on the way in if you'd like to see the work."
PER-CLUSTER BRIEF โ ๐ฅ #2 SUNSET GROVE (75070)
Opening line (script_personality = consultative_neighbor):
"Hi, I'm Jamie with Acme Roofing โ we've been walking roofs all morning over in
Maple Ridge, one subdivision north. Sunset Grove sits right under the same 4/18
hail core, and on the 12-to-18-year architectural roofs out here that's exactly
the age where 1.5-inch stones bruise the mat. No charge to walk yours and leave
you a written report โ you decide what to do with it."
Drive-in identifier: spatter marks on the painted ridge vent, granule wash at the
downspout splash blocks, soft metal dents on the AC condenser fins (a clean tell
on these rear-yard units even when the shingles look fine from the ground).
Likely objection: "We re-roofed maybe ten years ago, we're probably fine."
Response: "Ten-to-fifteen years is actually the sweet spot for functional hail
bruising โ the mat's lost enough flexibility to fracture but the roof still looks
good from the driveway. That's the case the camera and the strike count settle,
not the eyeball."
Hand-off moment: "I'll text you our scheduling link right now โ a 45-minute walk
in the next day or two, and you get the written report either way."
Compliance line (TX is in canvassing.cooling_off_states[]):
"TX gives you a 3-day right of rescission on anything signed at the door โ and
there's nothing to sign today. This is just booking a free inspection."
Adjacent social-proof (from past_jobs.completed_addresses[]):
"We finished 942 Sunset Grove Ln (the Alvarez home, GAF Timberline HDZ) last
spring โ two streets over, same build era. Glad to point you to it on the way in."
PER-CLUSTER BRIEF โ ๐ฅ #3 RIVERSIDE (75074)
Opening line (script_personality = consultative_neighbor):
"Hi, I'm Jamie with Acme Roofing โ we're working the Riverside pocket today after
the 4/18 storm. This neighborhood's a mix of 3-tab and architectural roofs, and the
older 3-tab takes hail harder than almost anything out there. Free roof walk and a
written report, no obligation โ homeowner decides the next step."
Drive-in identifier: full-slope granule loss on the south-facing 3-tab (shows as a
lightened, mottled patch from the street), lifted and creased tabs along the eave
course, dented gutter aprons at the corners.
Likely objection: "I want to get a couple of opinions before anyone's on my roof."
Response: "Smart โ get more than one. All we're doing today is documenting what's
actually up there with photos and a per-slope strike count, so whoever you compare
is comparing against the same evidence instead of a guess."
Hand-off moment: "Riverside is our phone-hybrid cluster โ if now's not good, our call
bank can lock a window that fits your schedule. I'll text the link so you've got it."
Compliance line (TX is in canvassing.cooling_off_states[]):
"TX requires a 3-day right of rescission on any door-signed contract โ you sign
nothing today, this is only scheduling a free inspection."
Adjacent social-proof (from past_jobs.completed_addresses[]):
"We replaced 3104 Riverside Dr (the Nguyen home, architectural, fast insurance
turnaround) in 2025 โ same streets, same storm exposure. Happy to show you that roof."
DAY-BY-DAY SCHEDULE
| Day | Date | Knockers (8) Coverage | Phone Bank (3) Coverage |
|-----|------------|--------------------------------------|----------------------------------|
| 1 | 2026-04-19 | Maple Ridge (5) + Sunset Grove (3) | Riverside warm-up (60 calls) |
| 2 | 2026-04-20 | Riverside (5) + Maple Ridge tail (3) | Willow Creek phone-first (90) |
| 3 | 2026-04-21 | Willow Creek door-tail (4) + recanvass missed (4) | Stonebridge mail follow-up (60) |
| 4โ7 | 2026-04-22+| Mail drop full polygon (~9,500 pieces) + Meta retargeting match list (6,400) | |
CANVASSER ASSIGNMENTS (from team.canvasser_roster[])
| Canvasser | Languages | Vehicle | Shift | Day-1 cluster | Cap |
|-------------|------------|---------|-------------|--------------------|-------|
| Jamie Reed | en | truck | 10:00โ18:00 | Maple Ridge | 50 |
| Luis Mora | en, es | van | 10:00โ18:00 | Maple Ridge (es) | 50 |
| Dee Carter | en | truck | 10:00โ18:00 | Maple Ridge | 50 |
| Priya Shah | en, es | on-foot | 12:00โ19:00 | Sunset Grove (es) | 40 |
| Marcus Hill | en | truck | 10:00โ18:00 | Sunset Grove | 50 |
| Sam Boone | en | van | 10:00โ18:00 | Riverside | 50 |
| Tyler Voss | en | truck | 10:00โ18:00 | Riverside | 50 |
| Ana Reyes | en, es | on-foot | 12:00โ19:00 | Riverside (es) | 40 |
| Phone bank (3): Kim O., Raj P., Chloe D. โ 75071/75075 phone-first, 60โ90 calls/shift |
MEASUREMENT TARGETS
- Day 1 doors knocked: 240 (90 + 70 + 80)
- Contact rate target: 40% โ 96 contacts
- Inspection booking target: 28% โ 27 inspections booked
- 30-day closed deal target: 35% of inspections โ 9 deals from Day 1 alone
ASSUMPTIONS
- canvassing.territories[] confirmed for Maple Ridge / Sunset Grove / Riverside / Willow Creek / Stonebridge
- canvassing.cooling_off_states[] = ["TX", "MI", "OK", "CO", "GA"] โ TX matched
- weather_rules.hail_size_threshold_in defaulted to 1.0; .wind_threshold_mph to 60
- team.canvasser_roster[] resolved 8 door knockers + 3 phone canvassers; bilingual (en/es) coverage on 3 (Luis, Priya, Ana), one assigned to each top-tier ๐ฅ cluster
- past_jobs.completed_addresses[] yielded 14 nearby completed jobs across the 5 territories
(Run with your own storm data + config to replace these illustrative values.)