Incantory
로그인

Sales Research

name: sales-research description: This skill provides methodology and best practices for researching sales prospects.

prompts.chatv1스타 0개 · 포크 0개 · 작품 0개≈5.9K 토큰

Sales Research

Overview

This skill provides methodology and best practices for researching sales prospects. It covers company research, contact profiling, and signal detection to surface actionable intelligence.

Usage

The company-researcher and contact-researcher sub-agents reference this skill when:

  • Researching new prospects
  • Finding company information
  • Profiling individual contacts
  • Detecting buying signals

Research Methodology

Company Research Checklist

  1. Basic Profile

    • Company name, industry, size (employees, revenue)
    • Headquarters and key locations
    • Founded date, growth stage
  2. Recent Developments

    • Funding announcements (last 12 months)
    • M&A activity
    • Leadership changes
    • Product launches
  3. Tech Stack

    • Known technologies (BuiltWith, StackShare)
    • Job postings mentioning tools
    • Integration partnerships
  4. Signals

    • Job postings (scaling = opportunity)
    • Glassdoor reviews (pain points)
    • News mentions (context)
    • Social media activity

Contact Research Checklist

  1. Professional Background

    • Current role and tenure
    • Previous companies and roles
    • Education
  2. Influence Indicators

    • Reporting structure
    • Decision-making authority
    • Budget ownership
  3. Engagement Hooks

    • Recent LinkedIn posts
    • Published articles
    • Speaking engagements
    • Mutual connections

Resources

  • resources/signal-indicators.md - Taxonomy of buying signals
  • resources/research-checklist.md - Complete research checklist

Scripts

  • scripts/company-enricher.py - Aggregate company data from multiple sources
  • scripts/linkedin-parser.py - Structure LinkedIn profile data FILE:company-enricher.py #!/usr/bin/env python3 """ company-enricher.py - Aggregate company data from multiple sources

Inputs:

  • company_name: string
  • domain: string (optional)

Outputs:

  • profile: name: string industry: string size: string funding: string tech_stack: [string] recent_news: [news items]

Dependencies:

  • requests, beautifulsoup4 """

Requirements: requests, beautifulsoup4

import json from typing import Any from dataclasses import dataclass, asdict from datetime import datetime

@dataclass class NewsItem: title: str date: str source: str url: str summary: str

@dataclass class CompanyProfile: name: str domain: str industry: str size: str location: str founded: str funding: str tech_stack: list[str] recent_news: list[dict] competitors: list[str] description: str

def search_company_info(company_name: str, domain: str = None) -> dict: """ Search for basic company information. In production, this would call APIs like Clearbit, Crunchbase, etc. """ # TODO: Implement actual API calls # Placeholder return structure return { "name": company_name, "domain": domain or f"{company_name.lower().replace(' ', '')}.com", "industry": "Technology", # Would come from API "size": "Unknown", "location": "Unknown", "founded": "Unknown", "description": f"Information about {company_name}" }

def search_funding_info(company_name: str) -> dict: """ Search for funding information. In production, would call Crunchbase, PitchBook, etc. """ # TODO: Implement actual API calls return { "total_funding": "Unknown", "last_round": "Unknown", "last_round_date": "Unknown", "investors": [] }

def search_tech_stack(domain: str) -> list[str]: """ Detect technology stack. In production, would call BuiltWith, Wappalyzer, etc. """ # TODO: Implement actual API calls return []

def search_recent_news(company_name: str, days: int = 90) -> list[dict]: """ Search for recent news about the company. In production, would call news APIs. """ # TODO: Implement actual API calls return []

def main( company_name: str, domain: str = None ) -> dict[str, Any]: """ Aggregate company data from multiple sources.

Args:
    company_name: Company name to research
    domain: Company domain (optional, will be inferred)

Returns:
    dict with company profile including industry, size, funding, tech stack, news
"""
# Get basic company info
basic_info = search_company_info(company_name, domain)

# Get funding information
funding_info = search_funding_info(company_name)

# Detect tech stack
company_domain = basic_info.get("domain", domain)
tech_stack = search_tech_stack(company_domain) if company_domain else []

# Get recent news
news = search_recent_news(company_name)

# Compile profile
profile = CompanyProfile(
    name=basic_info["name"],
    domain=basic_info["domain"],
    industry=basic_info["industry"],
    size=basic_info["size"],
    location=basic_info["location"],
    founded=basic_info["founded"],
    funding=funding_info.get("total_funding", "Unknown"),
    tech_stack=tech_stack,
    recent_news=news,
    competitors=[],  # Would be enriched from industry analysis
    description=basic_info["description"]
)

return {
    "profile": asdict(profile),
    "funding_details": funding_info,
    "enriched_at": datetime.now().isoformat(),
    "sources_checked": ["company_info", "funding", "tech_stack", "news"]
}

if name == "main": import sys

# Example usage
result = main(
    company_name="DataFlow Systems",
    domain="dataflow.io"
)
print(json.dumps(result, indent=2))

FILE:linkedin-parser.py #!/usr/bin/env python3 """ linkedin-parser.py - Structure LinkedIn profile data

Inputs:

  • profile_url: string
  • or name + company: strings

Outputs:

  • contact: name: string title: string tenure: string previous_roles: [role objects] mutual_connections: [string] recent_activity: [post summaries]

Dependencies:

  • requests """

Requirements: requests

import json from typing import Any from dataclasses import dataclass, asdict from datetime import datetime

@dataclass class PreviousRole: title: str company: str duration: str description: str

@dataclass class RecentPost: date: str content_preview: str engagement: int topic: str

@dataclass class ContactProfile: name: str title: str company: str location: str tenure: str previous_roles: list[dict] education: list[str] mutual_connections: list[str] recent_activity: list[dict] profile_url: str headline: str

def search_linkedin_profile(name: str = None, company: str = None, profile_url: str = None) -> dict: """ Search for LinkedIn profile information. In production, would use LinkedIn API or Sales Navigator. """ # TODO: Implement actual LinkedIn API integration # Note: LinkedIn's API has strict terms of service

return {
    "found": False,
    "name": name or "Unknown",
    "title": "Unknown",
    "company": company or "Unknown",
    "location": "Unknown",
    "headline": "",
    "tenure": "Unknown",
    "profile_url": profile_url or ""
}

def get_career_history(profile_data: dict) -> list[dict]: """ Extract career history from profile. """ # TODO: Implement career extraction return []

def get_mutual_connections(profile_data: dict, user_network: list = None) -> list[str]: """ Find mutual connections. """ # TODO: Implement mutual connection detection return []

def get_recent_activity(profile_data: dict, days: int = 30) -> list[dict]: """ Get recent posts and activity. """ # TODO: Implement activity extraction return []

def main( name: str = None, company: str = None, profile_url: str = None ) -> dict[str, Any]: """ Structure LinkedIn profile data for sales prep.

Args:
    name: Person's name
    company: Company they work at
    profile_url: Direct LinkedIn profile URL

Returns:
    dict with structured contact profile
"""
if not profile_url and not (name and company):
    return {"error": "Provide either profile_url or name + company"}

# Search for profile
profile_data = search_linkedin_profile(
    name=name,
    company=company,
    profile_url=profile_url
)

if not profile_data.get("found"):
    return {
        "found": False,
        "name": name or "Unknown",
        "company": company or "Unknown",
        "message": "Profile not found or limited access",
        "suggestions": [
            "Try searching directly on LinkedIn",
            "Check for alternative spellings",
            "Verify the person still works at this company"
        ]
    }

# Get career history
previous_roles = get_career_history(profile_data)

# Find mutual connections
mutual_connections = get_mutual_connections(profile_data)

# Get recent activity
recent_activity = get_recent_activity(profile_data)

# Compile contact profile
contact = ContactProfile(
    name=profile_data["name"],
    title=profile_data["title"],
    company=profile_data["company"],
    location=profile_data["location"],
    tenure=profile_data["tenure"],
    previous_roles=previous_roles,
    education=[],  # Would be extracted from profile
    mutual_connections=mutual_connections,
    recent_activity=recent_activity,
    profile_url=profile_data["profile_url"],
    headline=profile_data["headline"]
)

return {
    "found": True,
    "contact": asdict(contact),
    "research_date": datetime.now().isoformat(),
    "data_completeness": calculate_completeness(contact)
}

def calculate_completeness(contact: ContactProfile) -> dict: """Calculate how complete the profile data is.""" fields = { "basic_info": bool(contact.name and contact.title and contact.company), "career_history": len(contact.previous_roles) > 0, "mutual_connections": len(contact.mutual_connections) > 0, "recent_activity": len(contact.recent_activity) > 0, "education": len(contact.education) > 0 }

complete_count = sum(fields.values())
return {
    "fields": fields,
    "score": f"{complete_count}/{len(fields)}",
    "percentage": int((complete_count / len(fields)) * 100)
}

if name == "main": import sys

# Example usage
result = main(
    name="Sarah Chen",
    company="DataFlow Systems"
)
print(json.dumps(result, indent=2))

FILE:priority-scorer.py #!/usr/bin/env python3 """ priority-scorer.py - Calculate and rank prospect priorities

Inputs:

  • prospects: [prospect objects with signals]
  • weights: {deal_size, timing, warmth, signals}

Outputs:

  • ranked: [prospects with scores and reasoning]

Dependencies:

  • (none - pure Python) """

import json from typing import Any from dataclasses import dataclass

Default scoring weights

DEFAULT_WEIGHTS = { "deal_size": 0.25, "timing": 0.30, "warmth": 0.20, "signals": 0.25 }

Signal score mapping

SIGNAL_SCORES = { # High-intent signals "recent_funding": 10, "leadership_change": 8, "job_postings_relevant": 9, "expansion_news": 7, "competitor_mention": 6,

# Medium-intent signals
"general_hiring": 4,
"industry_event": 3,
"content_engagement": 3,

# Relationship signals
"mutual_connection": 5,
"previous_contact": 6,
"referred_lead": 8,

# Negative signals
"recent_layoffs": -3,
"budget_freeze_mentioned": -5,
"competitor_selected": -7,

}

@dataclass class ScoredProspect: company: str contact: str call_time: str raw_score: float normalized_score: int priority_rank: int score_breakdown: dict reasoning: str is_followup: bool

def score_deal_size(prospect: dict) -> tuple[float, str]: """Score based on estimated deal size.""" size_indicators = prospect.get("size_indicators", {})

employee_count = size_indicators.get("employees", 0)
revenue_estimate = size_indicators.get("revenue", 0)

# Simple scoring based on company size
if employee_count > 1000 or revenue_estimate > 100_000_000:
    return 10.0, "Enterprise-scale opportunity"
elif employee_count > 200 or revenue_estimate > 20_000_000:
    return 7.0, "Mid-market opportunity"
elif employee_count > 50:
    return 5.0, "SMB opportunity"
else:
    return 3.0, "Small business"

def score_timing(prospect: dict) -> tuple[float, str]: """Score based on timing signals.""" timing_signals = prospect.get("timing_signals", [])

score = 5.0  # Base score
reasons = []

for signal in timing_signals:
    if signal == "budget_cycle_q4":
        score += 3
        reasons.append("Q4 budget planning")
    elif signal == "contract_expiring":
        score += 4
        reasons.append("Contract expiring soon")
    elif signal == "active_evaluation":
        score += 5
        reasons.append("Actively evaluating")
    elif signal == "just_funded":
        score += 3
        reasons.append("Recently funded")

return min(score, 10.0), "; ".join(reasons) if reasons else "Standard timing"

def score_warmth(prospect: dict) -> tuple[float, str]: """Score based on relationship warmth.""" relationship = prospect.get("relationship", {})

if relationship.get("is_followup"):
    last_outcome = relationship.get("last_outcome", "neutral")
    if last_outcome == "positive":
        return 9.0, "Warm follow-up (positive last contact)"
    elif last_outcome == "neutral":
        return 7.0, "Follow-up (neutral last contact)"
    else:
        return 5.0, "Follow-up (needs re-engagement)"

if relationship.get("referred"):
    return 8.0, "Referred lead"

if relationship.get("mutual_connections", 0) > 0:
    return 6.0, f"{relationship['mutual_connections']} mutual connections"

if relationship.get("inbound"):
    return 7.0, "Inbound interest"

return 4.0, "Cold outreach"

def score_signals(prospect: dict) -> tuple[float, str]: """Score based on buying signals detected.""" signals = prospect.get("signals", [])

total_score = 0
signal_reasons = []

for signal in signals:
    signal_score = SIGNAL_SCORES.get(signal, 0)
    total_score += signal_score
    if signal_score > 0:
        signal_reasons.append(signal.replace("_", " "))

# Normalize to 0-10 scale
normalized = min(max(total_score / 2, 0), 10)

reason = f"Signals: {', '.join(signal_reasons)}" if signal_reasons else "No strong signals"
return normalized, reason

def calculate_priority_score( prospect: dict, weights: dict = None ) -> ScoredProspect: """Calculate overall priority score for a prospect.""" weights = weights or DEFAULT_WEIGHTS

# Calculate component scores
deal_score, deal_reason = score_deal_size(prospect)
timing_score, timing_reason = score_timing(prospect)
warmth_score, warmth_reason = score_warmth(prospect)
signal_score, signal_reason = score_signals(prospect)

# Weighted total
raw_score = (
    deal_score * weights["deal_size"] +
    timing_score * weights["timing"] +
    warmth_score * weights["warmth"] +
    signal_score * weights["signals"]
)

# Compile reasoning
reasons = []
if timing_score >= 8:
    reasons.append(timing_reason)
if signal_score >= 7:
    reasons.append(signal_reason)
if warmth_score >= 7:
    reasons.append(warmth_reason)
if deal_score >= 8:
    reasons.append(deal_reason)

return ScoredProspect(
    company=prospect.get("company", "Unknown"),
    contact=prospect.get("contact", "Unknown"),
    call_time=prospect.get("call_time", "Unknown"),
    raw_score=round(raw_score, 2),
    normalized_score=int(raw_score * 10),
    priority_rank=0,  # Will be set after sorting
    score_breakdown={
        "deal_size": {"score": deal_score, "reason": deal_reason},
        "timing": {"score": timing_score, "reason": timing_reason},
        "warmth": {"score": warmth_score, "reason": warmth_reason},
        "signals": {"score": signal_score, "reason": signal_reason}
    },
    reasoning="; ".join(reasons) if reasons else "Standard priority",
    is_followup=prospect.get("relationship", {}).get("is_followup", False)
)

def main( prospects: list[dict], weights: dict = None ) -> dict[str, Any]: """ Calculate and rank prospect priorities.

Args:
    prospects: List of prospect objects with signals
    weights: Optional custom weights for scoring components

Returns:
    dict with ranked prospects and scoring details
"""
weights = weights or DEFAULT_WEIGHTS

# Score all prospects
scored = [calculate_priority_score(p, weights) for p in prospects]

# Sort by raw score descending
scored.sort(key=lambda x: x.raw_score, reverse=True)

# Assign ranks
for i, prospect in enumerate(scored, 1):
    prospect.priority_rank = i

# Convert to dicts for JSON serialization
ranked = []
for s in scored:
    ranked.append({
        "company": s.company,
        "contact": s.contact,
        "call_time": s.call_time,
        "priority_rank": s.priority_rank,
        "score": s.normalized_score,
        "reasoning": s.reasoning,
        "is_followup": s.is_followup,
        "breakdown": s.score_breakdown
    })

return {
    "ranked": ranked,
    "weights_used": weights,
    "total_prospects": len(prospects)
}

if name == "main": import sys

# Example usage
example_prospects = [
    {
        "company": "DataFlow Systems",
        "contact": "Sarah Chen",
        "call_time": "2pm",
        "size_indicators": {"employees": 200, "revenue": 25_000_000},
        "timing_signals": ["just_funded", "active_evaluation"],
        "signals": ["recent_funding", "job_postings_relevant"],
        "relationship": {"is_followup": False, "mutual_connections": 2}
    },
    {
        "company": "Acme Manufacturing",
        "contact": "Tom Bradley",
        "call_time": "10am",
        "size_indicators": {"employees": 500},
        "timing_signals": ["contract_expiring"],
        "signals": [],
        "relationship": {"is_followup": True, "last_outcome": "neutral"}
    },
    {
        "company": "FirstRate Financial",
        "contact": "Linda Thompson",
        "call_time": "4pm",
        "size_indicators": {"employees": 300},
        "timing_signals": [],
        "signals": [],
        "relationship": {"is_followup": False}
    }
]

result = main(prospects=example_prospects)
print(json.dumps(result, indent=2))

FILE:research-checklist.md

Prospect Research Checklist

Company Research

Basic Information

  • Company name (verify spelling)
  • Industry/vertical
  • Headquarters location
  • Employee count (LinkedIn, website)
  • Revenue estimate (if available)
  • Founded date
  • Funding stage/history

Recent News (Last 90 Days)

  • Funding announcements
  • Acquisitions or mergers
  • Leadership changes
  • Product launches
  • Major customer wins
  • Press mentions
  • Earnings/financial news

Digital Footprint

  • Website review
  • Blog/content topics
  • Social media presence
  • Job postings (careers page + LinkedIn)
  • Tech stack (BuiltWith, job postings)

Competitive Landscape

  • Known competitors
  • Market position
  • Differentiators claimed
  • Recent competitive moves

Pain Point Indicators

  • Glassdoor reviews (themes)
  • G2/Capterra reviews (if B2B)
  • Social media complaints
  • Job posting patterns

Contact Research

Professional Profile

  • Current title
  • Time in role
  • Time at company
  • Previous companies
  • Previous roles
  • Education

Decision Authority

  • Reports to whom
  • Team size (if manager)
  • Budget authority (inferred)
  • Buying involvement history

Engagement Hooks

  • Recent LinkedIn posts
  • Published articles
  • Podcast appearances
  • Conference talks
  • Mutual connections
  • Shared interests/groups

Communication Style

  • Post tone (formal/casual)
  • Topics they engage with
  • Response patterns

CRM Check (If Available)

  • Any prior touchpoints
  • Previous opportunities
  • Related contacts at company
  • Notes from colleagues
  • Email engagement history

Time-Based Research Depth

Time AvailableResearch Depth
5 minutesCompany basics + contact title only
15 minutes+ Recent news + LinkedIn profile
30 minutes+ Pain point signals + engagement hooks
60 minutesFull checklist + competitive analysis
FILE:signal-indicators.md

Signal Indicators Reference

High-Intent Signals

Job Postings

  • 3+ relevant roles posted = Active initiative, budget allocated
  • Senior hire in your domain = Strategic priority
  • Urgency language ("ASAP", "immediate") = Pain is acute
  • Specific tool mentioned = Competitor or category awareness

Financial Events

  • Series B+ funding = Growth capital, buying power
  • IPO preparation = Operational maturity needed
  • Acquisition announced = Integration challenges coming
  • Revenue milestone PR = Budget available

Leadership Changes

  • New CXO in your domain = 90-day priority setting
  • New CRO/CMO = Tech stack evaluation likely
  • Founder transition to CEO = Professionalizing operations

Medium-Intent Signals

Expansion Signals

  • New office opening = Infrastructure needs
  • International expansion = Localization, compliance
  • New product launch = Scaling challenges
  • Major customer win = Delivery pressure

Technology Signals

  • RFP published = Active buying process
  • Vendor review mentioned = Comparison shopping
  • Tech stack change = Integration opportunity
  • Legacy system complaints = Modernization need

Content Signals

  • Blog post on your topic = Educating themselves
  • Webinar attendance = Interest confirmed
  • Whitepaper download = Problem awareness
  • Conference speaking = Thought leadership, visibility

Low-Intent Signals (Nurture)

General Activity

  • Industry event attendance = Market participant
  • Generic hiring = Company growing
  • Positive press = Healthy company
  • Social media activity = Engaged leadership

Signal Scoring

Signal TypeScoreAction
Job posting (relevant)+3Prioritize outreach
Recent funding+3Reference in conversation
Leadership change+2Time-sensitive opportunity
Expansion news+2Growth angle
Negative reviews+2Pain point angle
Content engagement+1Nurture track
No signals0Discovery focus