Turn existing customers into a search template → find similar businesses on Google Maps → enrich → score → output actionable call lists.
One line: Known customer → profile → Maps search → enrich & rank → CSV call list + JSON index
Before running this skill, confirm:
ItemRequirementGeographyOnly collect businesses in jurisdictions where B2B outreach is lawfulData source termsComply with Google Maps Terms of Service, Yelp ToS, and any site scrapedRate limitingAdd reasonable delays between requests; do not hammer the same siteDo-not-call / anti-spamRespect opt-out lists and local telemarketing rulesPrivacy lawsGDPR / CCPA / PIPL: avoid collecting unnecessary personal contact infoData accuracyOnly use publicly listed business contact info; do not enrich personal mobile numbers or home addresses
This skill collects publicly visible business information only. Do not use it to harvest personal emails, mobile phones, home addresses, or non-business contacts.
RuleImplementationOutput pathprospect-data/{batch}/ under the user's workspaceRetentionDelete or archive prospect files when the campaign ends or they are no longer activeSensitive dataDo not store personal mobile numbers or non-business contactsSharingDo not share raw JSON/CSV with third parties without consentEncryptionMove completed batches to encrypted storage if required by your policyAccessTreat call lists and profile JSON as internal sales data; restrict access to authorized users
FieldRequiredNotesCompany name✅Core search termLocation (city/state)✅Search center pointProduct purchased❌Helps with profiling
Even minimal input ("Bob's Auto Body, Orange CA") can start the full flow.
Before executing searches, the skill automatically analyzes search parameters and adjusts strategy without user intervention:
After initial search round completes, automatically check for these warning signals:
Warning SignalThresholdAuto-ActionZero results for keyword+center0 listings returnedSwap keyword (e.g., "paint shop" → "auto paint" / "car paint" / "collision")Low unique yield per center<5 unique businesses per center after dedupExpand radius or add satellite centerHigh non-target ratio>30% listings are wrong industryTighten keyword (e.g., "paint shop" → "auto body paint" / "collision paint")Chain under-representation0 chain brands in resultsAdd brand keywords (Caliber, CARSTAR, Maaco, Gerber)Equipment-related missingNo spray booth / frame machine in resultsAdd equipment keywords to second pass
text
IF center + "paint shop" returns <5 valid auto-body listings:
→ REPLACE with "auto paint shop" OR "car paint" OR "collision paint"
IF center + "auto body shop" returns 0 results:
→ TRY "body shop" OR "collision repair" OR "auto repair"
IF chain brands known in industry but missing from results:
→ ADD "[brand] + city" as explicit search (e.g., "Caliber Houston")
text
PASS 1: Core keywords (auto body shop, collision repair, paint shop)
↓
Auto-analyze coverage gaps
↓
PASS 2: Gap-fill keywords (adjusted based on PASS 1 results)
↓
PASS 3: Equipment/brand keywords (spray booth, frame machine, Caliber, CARSTAR)
↓
Final dedup + scoring
No user input required — the skill self-diagnoses and adjusts between passes.
Read references/profiling.md for the full 8-step process. Key actions:
[company name] [location], extract: address, phone, rating, review count, business type, hours, website, photos, chain statusnew, expand, equipment, upgrade, install, moved, bigger + industry-specific keywords (e.g., for auto body: paint booth, insurance, fleet, dealer)prospect-data/{batch}/profile-{name}.jsonTier detection (determines enrichment depth):
Read references/search-strategy.md for the complete search framework.
NEW: Self-Optimizing Search Loop
The search now runs in 3 automatic passes with gap detection between each:
text
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ PASS 1 │ │ PASS 2 │ │ PASS 3 │
│ Core keywords │────→│ Gap-fill │────→│ Equipment/ │
│ (4-6 per │ │ (auto-adjusted│ │ Brand deep │
│ center) │ │ based on P1) │ │ dive │
└─────────────────┘ └─────────────────┘ └─────────────────┘
↓ ↓ ↓
[Auto-analyze] [Auto-analyze] [Final dedup]
Coverage gaps Remaining gaps + Score
After Pass 1 completes, automatically check:
CheckConditionAuto-ActionZero-result centersAny center returned 0 listings for >2 keywordsAdd 1-2 satellite centers (midpoint between existing centers)Low-yield keywordsAny keyword returned <3 valid listings across all centersReplace with synonym (see Keyword Swap Table below)Missing chainsKnown chain brands not foundAdd explicit brand+city searchesGeographic holesLarge gaps between centersAdd midpoint center
Keyword Swap Table (auto-applied):
Original (low yield)Replacement 1Replacement 2Replacement 3paint shopauto paint shopcar paintcollision paintauto body shopbody shopcollision repairauto repaircollision centercollision repairauto body repaircrash repairframe machineauto framechassis repairstructural repairspray boothpaint boothauto paint boothHVLP booth
If target industry involves equipment (auto body, manufacturing, HVAC), automatically add:
spray booth, frame machine, car lift, CNC mill, etc.[Brand] + [City] for known chains (Caliber, CARSTAR, Maaco, Gerber, Crash Champions)Search execution:
Save to: prospect-data/{batch}/candidates-raw.txt (raw extraction log) + candidates.json (deduplicated)
Auto-optimization logging: After each pass, append to candidates-raw.txt:
text
[PASS-N-ANALYSIS] Center: X, Keyword: Y, Results: Z, Action: [none|swapped|expanded|added-brand]
Based on Maps data, assign tiers. Chain stores are NOT excluded — they are valid prospects with a different approach strategy.
NEW: Self-Validation Checklist (auto-executed before tiering)
Before finalizing candidates, automatically verify:
CheckAction if FailedDuplicate names with different addressesMark as chain locations, keep allSame name + same address appearing multiple timesDeduplicate, keep most completeBusiness type mismatch (e.g., "car wash" labeled as "collision")Re-classify or flag for manual reviewPhone placeholder pattern (555, 000, 1234)Flag as phone_status: unverified_placeholderAddress in different city than search centerVerify: satellite location vs data error
Auto-chain detection (no manual list needed):
text
IF name contains: Caliber, CARSTAR, Maaco, Gerber, Crash Champions, ProColor, 1st Choice
→ Mark as chain_brand: [detected brand]
IF same name appears in >2 different addresses across centers
→ Mark as chain_brand: [normalized name]
→ Set tier: "连锁-XX"
TierCriteriaNext action🔴 Chain/largeChain name OR >200 reviews OR multi-location detectedDeep enrichment + chain procurement strategy🟡 Mid-tierHas website, 50-200 reviewsMedium enrichment🟢 SmallNo website, <50 reviewsSkip enrichment
Chain store prospecting strategy — Read references/chain-strategy.md for the full three-call approach:
Key principles:
TierActionToolsTime🔴 ChainWebsite deep + LinkedIn + news search + chain procurement mappingagent-browser + agent-reach (Exa)3-5min each🟡 MidWebsite basics + FBagent-browser1-2min each🟢 SmallSkip — Maps data sufficient—0
Chain enrichment with agent-browser:
agent-browser open "[website URL]"agent-browser snapshot -i → extract Services, About, Staff, ContactChain news search with agent-reach:
text
mcporter call 'exa.web_search_exa(query: "[company name] expansion OR new location OR equipment", numResults: 5)'
Chain procurement mapping (chains only) — See references/chain-strategy.md for full approach:
Match each candidate against the profile card:
FactorRulePointsBuy signalExpansion / new service / new equipment+5 (strong) / +3 (medium) / +1 (weak)Industry matchBusiness type matches profile+3Scale matchReview count / bays similar to profile+2Service overlapSame services as profile+2Geo similaritySimilar area type+1Business ageSimilar years in operation+1Chain multiplierChain store (multiple locations = bulk potential)+3EV/high-end certificationEV Certified / LUXE / premium line+4
Tie-breaking: buy signal strength → chain (bulk potential) → has phone → closer scale match
Total scorePriorityAction10+🔴 HighCall within 48h6-9🟡 MediumCall this week<5🟢 LowCall when available
Not templates — custom for each prospect based on their data.
Opener must accomplish 3 things: (1) prove you know them, (2) state your purpose, (3) invite dialogue.
Data sourceHow to use in openerBuy signal"Saw you just added [service related to your product]"Similar customer"We supplied [product] to [similar customer] in your area"Business type"Since you do [their business type]..."Key clues"As an [industry certification] shop..." / "Working with [their key client]..."TierHigh→emphasize quality & custom, Mid→value, Low→entry-levelChain store****Key opener question: "Is equipment purchasing handled locally, or should I speak with your regional/corporate procurement team?"Premium/certified lineReference their specialization: "As an EV-certified shop, you need [specific configuration] — we've done those."
Save to prospect-data/{batch}/:
text
prospect-data/{area}-{date}/
├── index.json ← Lightweight index, instant search
├── P001.json ← Full detail for first prospect
├── P002.json ← Full detail for next prospect
└── call-list.csv ← 11-column CSV for calling
See examples/ for sample output files.
Then export CSV from index + P###.json files for calling.
index.json — Search/filter only (few KB):
json
{
"batch_id": "orange-ca-2026-05-19",
"source_customer": "ABC Auto Body",
"generated": "2026-05-19",
"search_areas": ["Orange CA"],
"product": "Customizable per industry",
"chain_strategy": "Chain stores included — call local first to identify procurement decision chain, then escalate to regional/corporate",
"prospects": {
"P001": {
"name": "Bob's Auto Body",
"city": "Orange CA",
"priority": "高",
"tier": "中高端-独立",
"status": "待联系",
"tags": ["[industry]", "[business type]"],
"file": "P001.json"
},
"P013": {
"name": "Crash Champions Orange",
"city": "Orange CA",
"priority": "高",
"tier": "连锁-中高端",
"status": "待联系",
"tags": ["collision", "chain", "Crash Champions"],
"file": "P013.json"
}
}
}
P001.json — Full detail (all collected data + contact log):
json
{
"id": "P001",
"name": "Bob's Auto Body",
"phone": "[EXTRACTED_FROM_MAPS]",
"city": "Orange CA",
"tier": "Mid-high-Independent",
"priority": "High",
"buy_signal": "Added new [service]",
"similar_customer": "Customer A",
"business_type": "[industry service type]",
"key_clues": "[specific observations from data]",
"email": "bob@bobscorp.com",
"chain_brand": null,
"opener": "We supplied [product] to [similar customer] in your area — saw you recently added [service]. What [product type] are you currently using?",
"status": "Pending",
"contact_log": [],
"tags": ["[industry]", "[business type]", "[certification]"],
"maps_url": "https://maps.google.com/...",
"rating": 4.5,
"reviews_count": 87,
"has_website": true,
"website_url": "https://bobscorp.com",
"raw_notes": "Reviews mention...",
"source_customer": "Customer A"
}
P013.json — Chain store example:
json
{
"id": "P013",
"name": "[Chain Brand] [City]",
"phone": "[EXTRACTED_FROM_MAPS]",
"city": "Orange CA",
"tier": "Chain-Mid-high",
"priority": "High",
"buy_signal": "National chain with stable equipment needs across locations",
"similar_customer": "Customer A",
"business_type": "[Industry] Chain",
"key_clues": "[Chain brand] national chain + [city] location + online booking",
"email": "",
"chain_brand": "[Chain Brand]",
"opener": "Hi, I'm with [company] — we manufacture [product]. [Chain brand] has a location here, and I'd like to learn about your equipment purchasing process. Is that handled locally, or should I speak with your regional/corporate procurement team?",
"status": "Pending",
"contact_log": [],
"tags": ["[industry]", "chain", "[chain brand]", "online booking"],
"maps_url": "https://maps.google.com/...",
"rating": 4.6,
"reviews_count": 120,
"has_website": true,
"website_url": "https://www.chainbrand.com",
"raw_notes": "National chain. Key question: local manager vs regional purchasing.",
"source_customer": "Customer A"
}
CSV export — 11 columns, ready to call:
text
优先级,店名,电话,城市,档位,购买信号,相似客户,业务类型,关键线索,邮箱,开场白
CSV columns map 1:1 to P###.json fields (priority→tier, etc.). CSV is a projection of the JSON, not a separate data source.
Status tracking (in P###.json, not CSV):
text
待联系 → 已联系 → 意向 / 无意向 / 回访中
↘ 无人接听 → 再试
When user reports call results, update P###.json:
json
"contact_log": [
{"date": "2026-05-20", "action": "电话", "result": "无人接听", "next": "明后天再试"}
]
And update index.json status field accordingly.
Re-export CSV filtered by status when user needs a new call list.
"unknown", "not found", or "pending verification". If a search returns no results or fails due to network issues, report this honestly to the user instead of generating placeholder data.raw_notes and adjust the priority accordingly. Do not fill gaps with assumptions."phone_status": "unverified_placeholder".555, 0000, 1234, or similar placeholder pattern must be marked "phone_status": "unverified_placeholder" and must not be written to the call-list.csv dial column."do_not_contact". Identify caller, company, and purpose on every call.candidates-raw.txt with [PASS-N-ANALYSIS] markers.coverage-report.json documenting: (a) which center+keyword combinations returned zero results, (b) which auto-adjustments were applied, (c) estimated coverage percentage of target businesses in the area. This helps users assess completeness without manual review.candidates-raw.txt.chain-brands-detected.json per search session. If a brand appears in >2 locations, add it to the known chain list for future searches. Share learnings across sessions via MEMORY.md updates.End of SKILL.md