dispo-blast skill

Role: the buyer-side broadcast lane. After a deal moves to dispo (HubSpot dispo pipeline 816046), this skill blasts to qualified buyer cohorts across 4 channels.

This skill wraps existing code: dispo-blast-engine.js (canonical 4-channel engine) + per-channel scripts + the InvestorBase scoring lib.

⚡ Execution-mode model routing (G-MODEL-ROUTING-AT-EXEC)

This skill is execution-mode by definition. Per CLAUDE.md “MANDATORY: Execution-Mode Model Routing” + feedback_model_routing_at_exec.md:

Step 1 of every invocation: decompose the work and dispatch via the Agent tool with model: "sonnet" using the 8-element prompt contract (task goal, evidence, tool to use, test requirements, acceptance criteria, rollback command, rule constraints, output format).

Opus (main conversation) role = dispatcher + verifier + Henry-gate. Direct Opus script invocation / code edits = governance violation unless the work fails the Sonnet rubric (novel architecture, rule arbitration, Henry decision gate, first instance of a new pattern). Action-gate per CLAUDE.md still requires Henry approval for any live blast regardless of which model drafted the call — NEVER run without --dry-run unless user explicitly authorizes live blast. Verify each subagent report against acceptance criteria before marking complete.

Architecture

HubSpot dispo deal (status: dispositioning) OR scheduled showing
        │
        ▼
[dispo-blast-engine.js] — unified 4-channel coordinator
        │
        ├─ Channel 1: Showing-day blast (ALL prior buyers + watchlist)
        │     └─ [showing-blast-generic.js] / [showing-blast-compiled.js]
        │
        ├─ Channel 2: CRMLS agents
        │     └─ [dispo-crmls-agent-blast.js]
        │     └─ Targets agents who recently sold in zip + price band
        │
        ├─ Channel 3: InvestorBase end-buyers
        │     └─ [dispo-investorbase-blast.js]
        │     └─ [ib-blast-scorer.js] — fit score per buyer (zip, beds, price band, condition prefs)
        │     └─ [ib-blast-history.js] — 4 dedup checks before blast
        │     └─ [ib-blast-message.js] — channel-specific message builder
        │
        ├─ Channel 4: PropStream flippers (cold)
        │     └─ [dispo-propstream-blast.js]
        │     └─ Targets flippers in market with 3+ recent purchases
        │
        ▼
[dispo-send.js] — same chokepoint as acquisitions-outreach
        │
        ▼
SalesMsg / OpenPhone

PRE-BLAST PREVIEW:
[blast-preview.js] — shows estimated count, cost, dedup hits before triggering

4-channel breakdown

#ChannelBuyer cohortSource dataDedup window
1Showing-dayAll prior buyers + watchlistHubSpot Contacts tagged ‘buyer’24h pre-showing
2CRMLS agentsActive LA agentsCRMLS API (recent sales by zip+price)30d per agent
3InvestorBaseEnd-buyers in our InvestorBase platformInvestorBase API (workspace/scripts/lib/investorbase/)7d per (deal, buyer)
4PropStreamCold flippers w/ recent activityPropStream API (zip + recent_purchases ≥3)90d per flipper

InvestorBase scoring (Channel 3 detail)

ib-blast-scorer.js fit score per buyer:

FactorWeightThreshold
Zip match25%exact zip OR adjacent zip
Bed count15%±1 bed
Price band20%within ±20% of asking
Condition pref20%matches buyer’s stated rehab tolerance
Recent activity10%bought in last 90d
Deal velocity10%hot deal (views > 100 in 24h)

Buyers with score ≥60 receive blast. Buyers below threshold are logged but skipped.

Pre-blast history checks (ib-blast-history.js — 4 checks)

Before any send to a buyer:

  1. Already-blasted check — sent this exact deal to this buyer in last 7d?
  2. Recent-engagement check — buyer responded to ANY blast in last 14d? (yes = quieter, lower priority)
  3. Saturation check — sent ≥3 blasts to this buyer in last 7d? (yes = skip)
  4. Suppression check — buyer in suppression list?

Any check fails → blast skipped, reason logged.

Capabilities (entry points)

Unified 4-channel blast — dispo-blast-engine.js

node /home/opsadmin/.openclaw/workspace/scripts/dispo-blast-engine.js \
  --deal-id=<HS dispo deal ID> \
  [--channels=1,2,3,4]   # default: all 4
  [--limit-per-channel=200]
  [--dry-run]

Per-channel scripts (use when targeting a single channel)

# Channel 2 — CRMLS agents
node /home/opsadmin/.openclaw/workspace/scripts/dispo-crmls-agent-blast.js \
  --deal-id=X --dry-run
 
# Channel 3 — InvestorBase end-buyers
node /home/opsadmin/.openclaw/workspace/scripts/dispo-investorbase-blast.js \
  --deal-id=X --min-score=60 --dry-run
 
# Channel 4 — PropStream flippers
node /home/opsadmin/.openclaw/workspace/scripts/dispo-propstream-blast.js \
  --deal-id=X --zip=33101 --dry-run

Showing-day blasts

# Generic showing-day announcement
node /home/opsadmin/.openclaw/workspace/scripts/showing-blast-generic.js --deal-id=X --dry-run
 
# Compiled (multi-deal, weekly)
node /home/opsadmin/.openclaw/workspace/scripts/showing-blast-compiled.js --week=2026-W17 --dry-run

Weekly inventory broadcast — w4-broadcast-blast.js

Wednesday morning summary of all deals in pipeline to all buyer cohorts:

node /home/opsadmin/.openclaw/workspace/scripts/w4-broadcast-blast.js --dry-run

Pre-blast preview — blast-preview.js

Shows estimated count, cost, dedup hits before triggering the actual blast:

node -e "
const p = require('/home/opsadmin/.openclaw/workspace/scripts/lib/blast-preview.js');
p.preview({ dealId: 'X', channels: [3, 4] }).then(r => console.log(JSON.stringify(r, null, 2)));
"

Blast response audit — audit-blast-responses.js

Post-blast: which buyers replied, how, classification:

node /home/opsadmin/.openclaw/workspace/scripts/audit-blast-responses.js \
  --deal-id=X

Triggers

User says any of:

  • “blast deal X to buyers”
  • “send to InvestorBase”
  • “showing day blast for X”
  • “weekly w4 broadcast”
  • “PropStream cold blast”
  • “CRMLS agent blast”
  • “audit blast responses for X”

For Stage 1 outreach to CH (acquisitions side), route to acquisitions-outreach skill.

Capabilities NOT in this skill

CapabilityLives in
CH-side acquisition outreachacquisitions-outreach skill
Reply handling for blast responsesacquisitions-followup skill (handles inbound from any channel)
HubSpot deal creationhubspot-deal-ingest skill
Buyer onboarding to InvestorBaseInvestorBase platform UI (separate)

Failure modes

SymptomCauseRecovery
0 buyers matched for IB blastscoring threshold too highlower --min-score; check buyer database freshness
429 from SalesMsg/OpenPhoneline saturationlower --limit-per-channel; rotate lines
CRMLS API auth failtoken rotatedrefresh from 1P; check master.env CRMLS section
PropStream rate limithit daily quotaretry tomorrow; check quota in master.env
Blast went to suppressed buyerhistory check missedcheck messaging_suppression table; surface for manual review
Inbound replies not routing backwebhook handler downcheck acquisitions-followup skill (it handles all inbound)

Memory cross-references

  • workspace/scripts/dispo-blast-engine.js — unified 4-channel coordinator
  • workspace/scripts/dispo-crmls-agent-blast.js — Channel 2
  • workspace/scripts/dispo-investorbase-blast.js — Channel 3
  • workspace/scripts/dispo-propstream-blast.js — Channel 4
  • workspace/scripts/showing-blast-generic.js / showing-blast-compiled.js — Channel 1
  • workspace/scripts/w4-broadcast-blast.js — weekly inventory
  • workspace/scripts/audit-blast-responses.js — post-blast audit
  • workspace/scripts/lib/investorbase/ib-blast-scorer.js — fit scoring
  • workspace/scripts/lib/investorbase/ib-blast-history.js — 4-check dedup
  • workspace/scripts/lib/investorbase/ib-blast-message.js — message builder
  • workspace/scripts/lib/blast-preview.js — pre-blast stats
  • workspace/knowledge-base/investorbase/API.md — InvestorBase API reference