agentsclimarketplace

Skill

Skill Hectelion-SA/claude-investor-shortlist/skill

Claude Code skill that builds branded M&A / fundraising investor shortlists — local DBs + Outlook + Firecrawl + Dropcontact → Excel with 31-column transaction pipeline.

Install
npx -y skills add Hectelion-SA/claude-investor-shortlist --skill skill

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Build a structured Excel investor shortlist (M&A or fundraising mandate) by combining local investor databases, Outlook contacts, web search (Firecrawl) and email enrichment (Dropcontact). Output is a 2-tab .xlsx (branded cover page + 31-column investor table with full transaction pipeline). Trigger when the user says "build an investor list", "investor shortlist", "shortlist for X", "M&A target list", or invokes /investor-shortlist.

SKILL.md

14.8 KB, as published. Nobody here has run it

Skill: /investor-shortlist — Investor Shortlist Builder

Objective

Full pipeline questionnaire → multi-source research → Dropcontact + Outlook + Firecrawl enrichment → branded Excel output with transaction pipeline columns.

The output file matches a standardized M&A advisory format used for sell-side, buy-side and fundraising mandates.

Configuration is read from config.yaml in the same folder as this skill. See config.example.yaml for the schema. Important keys:

  • dropcontact.api_key (or env DROPCONTACT_API_KEY)
  • local_databases — list of Excel files to scan
  • output.default_folder — suggested save path
  • brand.* — firm name, colors, font for the cover page + table

Step 1 — Structured questionnaire (MANDATORY before any action)

Ask ALL questions below, grouped in 2-3 AskUserQuestion calls, never as bullet plain-text. If the user skips a question, re-ask with an explicit default value.

Block A — Target company & mandate

  1. Client company name (e.g. "Acme SA") + website (e.g. "acme.com")
  2. Company country: 🇨🇭 Switzerland / 🇫🇷 France / 🇲🇨 Monaco / 🇱🇺 Luxembourg / Other
  3. Mandate type:
    • Fundraise (capital growth, product development, geographic expansion)
    • M&A sell-side (full or partial sale)
    • M&A buy-side (external growth — target search)
    • Refinancing / Debt (senior, mezzanine)
    • Restructuring (capital, debt)

Block B — Target profile

  1. Sector: e.g. "Real estate / Construction", "Industrial", "Tech / SaaS", "Healthcare / MedTech", "Energy", "B2B services", etc.

  2. Sub-sector (optional): e.g. "Residential development", "B2B HR SaaS"

  3. If Fundraise → Round:

    • Pre-seed (<500k)
    • Seed (500k - 2M)
    • Series A (2-10M)
    • Series B (10-30M)
    • Series C / Growth (>30M)
    • Late stage / Pre-IPO
  4. If M&A → Valuation range: e.g. "2-10M", "10-50M", "50-200M", "200M+"

Block C — Volume & typology

  1. Number of target investors in the shortlist: 15-20 / 20-30 / 30-50 / 50+
  2. Typology (multi-select):
    • Private / HNWI / Family offices
    • Financial institutional (PE funds, VC, AM, pension funds, banks)
    • Strategic / Industrial (sector players, competitors, suppliers/customers)
    • Public / Para-public (cantonal banks, sovereign funds, foundations)
  3. Investor geography: same country as target / pan-European / global

Block D — Sources & execution

  1. Source mix:
    • Local only (local Excel databases + Outlook contacts only)
    • Internet only (Firecrawl/Brave search + Dropcontact)
    • Hybrid (recommended — local + internet in parallel)
  2. Save path: ask for absolute Windows path, or propose default from config.yaml > output.default_folder
  3. Filename: auto-generated from config.yaml > output.filename_template or ask for custom

Step 2 — Multi-source research

2.1 — Local databases (if Local or Hybrid)

Read every file listed in config.yaml > local_databases. The skill auto-detects the header row by looking for columns matching patterns like:

  • company, name, firm, investor → investor name
  • email, mail, contact email → contact email
  • country, pays → country
  • focus, sector, theme, specialty → investment focus
  • phone, tel, mobile → phone
  • first name, prénom, last name, nom, surname → person

Filter by sub-sector / country / typology matching the brief. Score relevance 1-5.

If no local databases configured → skip this step and rely on internet + Dropcontact.

2.2 — Outlook contacts (Windows only, if outlook.scan_contacts: true)

Scan local Outlook contacts via PowerShell COM to identify investors already in your address book. Cross-reference by:

  • CompanyName (fuzzy match with identified investors)
  • Email domain (match with investor websites)

Reference PowerShell script (inline):

$outlook=New-Object -ComObject Outlook.Application
$ns=$outlook.GetNamespace("MAPI")
$contactsFolder=$ns.GetDefaultFolder(10)
$results=New-Object System.Collections.ArrayList
function ProcessFolder($folder, $list){
  foreach($item in $folder.Items){
    if($item.Class -eq 40){
      [void]$list.Add([PSCustomObject]@{
        FullName=$item.FullName; FirstName=$item.FirstName; LastName=$item.LastName
        CompanyName=$item.CompanyName; JobTitle=$item.JobTitle
        Email1=$item.Email1Address; Email2=$item.Email2Address
        BusinessPhone=$item.BusinessTelephoneNumber; MobilePhone=$item.MobileTelephoneNumber
        WebPage=$item.WebPage; Categories=$item.Categories
      })
    }
  }
  foreach($sf in $folder.Folders){ ProcessFolder $sf $list }
}
ProcessFolder $contactsFolder $results
foreach($store in $ns.Stores){
  try{
    $root=$store.GetRootFolder()
    foreach($f in $root.Folders){
      if($f.DefaultItemType -eq 2){ ProcessFolder $f $results }
    }
  }catch{}
}
$results | ConvertTo-Json -Depth 3 | Out-File -FilePath "$env:TEMP\_outlook_contacts.json" -Encoding utf8

Read the JSON in utf-8-sig (Windows BOM).

A hit in Outlook = the user already has a direct relationship with the contact → score boost, no Dropcontact call needed (Outlook email is more reliable than enriched email).

2.3 — Internet search (if Internet or Hybrid)

For each target with no clear decision-maker, use Firecrawl MCP (or your preferred web search) with focused queries:

"COMPANY_NAME" CEO managing director 2025 OR 2026
"COMPANY_NAME" managing partner OR président
"COMPANY_NAME" investor relations contact

Always double-check names (current CEO vs former, role changes, company rebrandings). Common pitfalls:

  • A CEO can have left up to 12 months ago — cross-check via news
  • Funds rebrand (e.g. acquisition-driven name changes) — verify current legal name
  • Asset managers often have multiple legal entities — pick the one matching the investment thesis

2.4 — Dropcontact enrichment (ALWAYS, unless Outlook email already validated)

API key from config.yaml > dropcontact.api_key or env DROPCONTACT_API_KEY. Never hardcode the key in the script.

Endpoint: POST https://api.dropcontact.io/batch

Payload:

{
  "data": [
    {"first_name": "First", "last_name": "Last", "company": "Company", "website": "domain.com"}
  ],
  "siren": false
}

Poll GET /batch/{request_id} every 15s (up to 40 attempts).

Returned fields: email[0].email, email[0].qualification (nominative@pro, catch-all@pro, not_found), phone[0].number.

Multi-pass strategy: if Dropcontact returns "Not found", search alternative decision-makers (CFO, Head of M&A, Managing Partner) via Firecrawl, then re-run Dropcontact.


Step 3 — Excel file generation

3.1 — File structure (2 tabs — NO Synthesis tab)

Tab 1: "Cover page" — minimal format (REQUIRED)

No content beyond the 6 lines below. Do NOT add enrichment sources, statistics, score legend, or important notes (this content goes in the chat summary post-generation, not in the file).

CellContentStyle
B2{brand.firm_name} (from config)font_family 14, primary_color, italic
B5{Client Company} — {Mandate type}font_family 25, primary_color
B6Investor shortlist {sector context}font_family 18, secondary_color, italic
B8Prepared for: {Title First Last [and Co-founder]}, {Company}font_family 11
B9Date: {DD MMM YYYY in English, e.g. "21 May 2026"}font_family 11
B10Targets: {N} investors {Country} ({typologies comma-separated})font_family 11

Concrete example (placeholder):

  • B2: "Acme M&A LLP"
  • B5: "Example SA — Series A+ Fundraise"
  • B6: "Investor shortlist MedTech / FemTech Switzerland"
  • B8: "Prepared for: Dr. John Doe and Jane Smith, Example SA"
  • B9: "Date: 21 May 2026"
  • B10: "Targets: 48 investors Switzerland (financial, family offices, strategic, public)"

Tab 2: "Investors" — 31 columns (header row = 4)

Identification block (cols 1-14):

  1. # (rank)
  2. Category (e.g. "Developer / Promoter CH", "Asset Manager RE CH", "Pension fund CH", etc.)
  3. Investor (legal name)
  4. Country (with flag emoji)
  5. City / Region
  6. Type (e.g. "Real estate developer", "Listed RE fund manager")
  7. Focus / Specialty (sector detail + ticket size)
  8. Civ. (Mr / Ms)
  9. First name
  10. Last name
  11. Title / Role
  12. Email (hyperlink mailto:)
  13. Phone
  14. Website (hyperlink https://)

Scoring block (col 15): 15. Score (1-5 with color coding from brand.accent_*: 5=green, 4=pale blue, 3=grey, 2=orange)

Transaction pipeline block (cols 16-31): 16. Type (empty at creation — fill manually: "Hot lead", "Warm lead", etc.) 17. Status (empty — "Not contacted", "Contacted", "Replied", "Meeting", "Pitch", "DD", "Closed-Won", "Closed-Lost") 18. Contacted by (initials — from defaults.prepared_by_initials) 19. Last contact (date of last exchange) 20. First intent email sent (X = sent) 21. Email date 22. Teaser sent (X) 23. NDA sent (X) 24. Teaser & NDA date 25. IM and process letter sent (X) 26. IM & process letter date 27. Management presentation (pitch) date 28. MBO/LOI reception date 29. Dataroom opening 30. Signing 31. Closing

All pipeline columns (16-31) are empty at creation — filled in as the transaction progresses.

IMPORTANT: do NOT create a "Synthesis" tab. The file contains only 2 tabs: "Cover page" + "Investors". The statistical summary (count by category, email quality, etc.) is delivered in the post-generation chat message, not in the file.

3.2 — Branding (from config.yaml)

Read brand.* from config.yaml. Defaults shown below match Hectelion SA original styling; override in config for your firm.

# Loaded from config['brand']:
primary_color    = "182E4E"   # main navy
secondary_color  = "0E2841"   # darker navy
accent_pale      = "DCEAF7"   # score 4
accent_green     = "6FCF9A"   # score 5
accent_orange    = "FFC000"   # score 2
accent_grey      = "F2F2F2"   # score 3
alert_red        = "C00000"   # alerts
border_grey      = "D9D9D9"   # cell borders
font_family      = "Cardo"    # cover page + table

# Grid: Cover page 25 / 18 / 14 / 11
# Table: header 11 bold white, data 10 (dense cells)
# Same font across the whole file — single source of truth.

3.3 — Header row style (Investors table)

  • Fill: primary_color solid
  • Text: White, font_family 11pt Bold
  • Alignment: left, center vertical, wrap_text
  • Border: thin border_grey
  • Header row height: 32

3.4 — Data rows (Investors table)

  • Font: font_family 10pt
  • Investor (col 3): font_family 10pt Bold primary_color
  • Email (col 12): hyperlink mailto, font_family 10pt color #0563C1 underline
  • Website (col 14): hyperlink https, font_family 10pt color #0563C1 underline
  • Score (col 15): centered, font_family 10pt primary_color bold, fill by value
  • Data row height: 70 (wrap text)
  • Freeze panes: header row + first 3 columns

Step 4 — Save

  1. Verify destination folder exists; create it if not
  2. If file already open in Excel: close Excel via PowerShell Get-Process EXCEL | ForEach-Object { $_.CloseMainWindow() } before saving
  3. Save the .xlsx file
  4. Optionally open the file automatically: Start-Process "{path}"
  5. Confirm to the user with a clickable markdown link: [{filename}.xlsx]({relative_or_absolute_path})

Step 5 — Final report to the user

After generation, present:

## Enrichment summary

**N/Total operational emails (X%)**

| Source | Count |
|---|---|
| ✅ Dropcontact nominative | ... |
| 🟦 Dropcontact catch-all  | ... |
| 📇 Outlook (your base)    | ... |
| ⚠ Standard to confirm    | ... |
| ❓ To clarify             | ... |

## Top X high-priority targets (score 5)
1. ...
2. ...

List any emails not found + reason (opaque public funds, low-visibility companies, etc.) with a recommended action (LinkedIn DM, formal letter, etc.).


Best practices

Deduplication

  • Before export, dedup by email (one email = one row max)
  • If same company but 2 decision-makers: keep the most senior / sector-relevant
  • NEVER contact 2 people at the same company with separate emails

Contact details

  • If Dropcontact email = catch-all@pro → flag in column, keep but mark
  • If not found → fallback info@{domain} + alternative decision-maker search (CFO, MD)
  • Phone: prefer direct mobile if Dropcontact returns one

Name verification

  • Always validate that the decision-maker currently holds the position (CEOs change)
  • Cross-reference Dropcontact name with Firecrawl news if any doubt
  • For large institutions: scan the latest annual report / press release if available

LinkedIn fallback

  • For non-Outlook contacts, optionally add a "LinkedIn" column with a pre-generated search URL: https://www.linkedin.com/search/results/people/?keywords={urllib.parse.quote(f"{first} {last} {company}")}
  • Cell display: "🔗 Search" hyperlink colored #0A66C2

Data security

  • NEVER commit the Dropcontact API key to a public repo (config.yaml is in .gitignore)
  • Excel files containing emails and phones should be treated as confidential client data
  • Save shortlists to a controlled folder (OneDrive/SharePoint with client access controls)

Reference script

See build_shortlist.py in this skill folder — Python reference implementation, configurable via config.yaml.


Anti-patterns to avoid

  • ❌ Skipping the questionnaire and inventing a generic list
  • ❌ Calling Dropcontact without checking Outlook first (existing contacts are highest quality)
  • ❌ Defaulting all emails to info@ out of laziness — always try Dropcontact first
  • ❌ Hardcoding the Dropcontact API key in the script — use config.yaml or env var
  • ❌ Hardcoding firm branding in the script — read from config.brand
  • ❌ Creating a "Synthesis" tab — the file has EXACTLY 2 tabs (Cover + Investors); the stats summary goes in the chat
  • ❌ Overloading the cover page (sources, score legend, statistics) — minimal format, 6 lines only (B2/B5/B6/B8/B9/B10)
  • ❌ Keeping rows with no email — by default, filter all rows without operational email before export (unless user explicitly asks to keep them)
  • ❌ Forgetting the pipeline columns (16-31) — that's the main value-add of the file
  • ❌ Listing CEO names without verifying they're still in post
  • ❌ Skipping the cover page — it's the visual recap of the file

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.