mcpField
V
vc-finder

vc-finder

github.com/varnan-techその他68744 回インストール2 週間前に更新
リポジトリ

vc-finder について

vc-finderは、投資家を探す創業者向けのリサーチスキルです。類似する資金調達済み企業や投資家、VCの投資方針を調べ、出典付きの候補リストと連絡の切り口を提示します。情報は検索結果または製品ページで確認できるものに限定します。

主な機能

  1. 01業界、段階、顧客層の分類
  2. 02類似する資金調達済み企業5社の検索
  3. 03類似企業の投資家調査
  4. 04関連するVCの投資方針の検索
  5. 05出典付き候補と連絡の切り口の提示
  6. 06検証可能な情報に限定

活用シーン

  1. 01スタートアップの投資家探し
  2. 02類似企業を通じたファンドの調査
  3. 03投資方針に基づくVCの選定
  4. 04個別性のある投資家への連絡準備

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/varnan-tech/opendirectory --skill vc-finder

インストール後、Claude Code で/vc-finderを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

.env.example
README.md
data/
vc_funds.json
evals/
evals.json
references/
stage-signals.md
vc-outreach-guide.md
scripts/
match_funds.py

詳細

VC Finder

製品の URL または説明を入力します。業界とステージを特定します。資金調達済みの類似企業を 5 社探します。2 つの調査トラックを実行します。類似企業に投資した VC(トラック A)と、この分野に関する投資方針を公開している VC(トラック B)を調べます。出典付きで順位付けした投資家リストと、アプローチのきっかけを返します。


ハルシネーションゼロのポリシー: 出力内のすべての事実は、特定の Tavily 検索結果または取得した製品ページまでたどれる必要があります。これは次の項目に適用されます。

  • 類似企業名:AI の学習知識ではなく、Tavily の検索結果に記載されている必要があります
  • VC ファンド名:Tavily の検索結果にそのまま記載されている必要があります
  • 投資額、注力ステージ、ポートフォリオ企業:AI の知識ではなく、検索スニペットから取得する必要があります
  • ファンドの概要と投資方針の要約:検索スニペットのみから抽出してください。検索データに詳細がない場合は、「検索データに見つかりません」と記載してください。学習知識から補完してはいけません。

よくある間違い

エージェントがやりがちなことそれが誤りである理由
有名だからといって a16z や Sequoia を追加する根拠のない有名 VC はノイズです。この製品に関する Tavily 検索結果に登場する VC だけを含めてください。名前を挙げるだけでは、創業者の時間を無駄にします。
学習知識から類似企業を生成する類似企業は Tavily 検索結果(ステップ 6)から取得する必要があります。企業に関する AI の知識は根拠になりません。記憶から提案された企業は、資金調達状況が誤っていたり、本当に類似していなかったりする可能性があります。
トラック A の検索が 5 件すべて 0 件でも続行するトラック A の結果が 0 件ということは、類似企業が不適切だったか、知名度が低すぎたということです。停止して、より幅広い検索クエリでステップ 6 を再実行し、再試行してください。
記事や投稿を引用せずにトラック B の VC を含める出典のない投資方針は、ハルシネーションと見分けがつきません。創業者は検証できず、リストの信頼性が失われます。
学習知識からファンドの概要を補完するファンドの概要は、Tavily のスニペットのテキストのみを使用する必要があります。スニペットにファンドの説明がない場合は、「検索データに見つかりません」と記載してください。
ウェブサイトの見た目からステージを特定するステージは、ステップ 4 で検出した具体的な CTA シグナルに基づく必要があります。
ありきたりなアプローチのきっかけを書くアプローチのきっかけには、必ずこの製品固有の差別化要素と、検索データにある具体的な VC のポートフォリオシグナルまたは投資方針の引用を含めてください。
ユーザーが説明も提供したからといって URL の取得を省略する必ず URL を取得してください。公開中のページからは、ユーザーの説明に含まれていないステージのシグナルが見つかることがよくあります。

ステップ 1:セットアップの確認

echo "TAVILY_API_KEY:    ${TAVILY_API_KEY:+set}"
echo "FIRECRAWL_API_KEY: ${FIRECRAWL_API_KEY:-not set, Tavily extract will be used as fallback}"

TAVILY_API_KEY がない場合: 停止してください。ユーザーに次のように伝えます。「VC の投資と投資方針を調査するには TAVILY_API_KEY が必要です。代替手段はありません。app.tavily.com で取得できます。無料枠は月 1000 クレジット(完全な実行約 125 回分)です。.env ファイルに追加してください。」

FIRECRAWL_API_KEY だけがない場合: 何も伝えずに続行します。URL の取得には Tavily の抽出機能を使用します。


ステップ 2:入力情報の収集

必要な情報:

  • 製品 URL(必須。ただし、ユーザーが製品の説明を直接貼り付ける場合を除きます)
  • 任意:対象ステージのヒント(pre-seed、seed、series-a、series-b)。指定されている場合はそれを使用し、ステージの検出を省略します
  • 任意:地域の希望(US、Europe、global)。指定がない場合は US が既定です

ユーザーが貼り付けた説明のみを提供した場合(URL なし): ステップ 3~4 を省略します。貼り付けられたテキストを product_content として、ステップ 5 に進みます。stage_source を user_description に設定します。

URL も説明も提供されていない場合: 次のように尋ねます。「製品またはスタートアップの URL を教えてください。または、製品の内容、対象者、現在のステージ(pre-seed、seed、Series A)を含む短い説明を貼り付けてください。」

出力ファイル名用に、URL から製品のスラッグを導出します。

PRODUCT_SLUG=$(python3 -c "
from urllib.parse import urlparse
url = 'URL_HERE'
host = urlparse(url).netloc.replace('www.', '')
print(host.split('.')[0])
")

ステップ 3:製品ページを取得する

優先:Firecrawl(FIRECRAWL_API_KEY が設定されている場合)

curl -s -X POST https://api.firecrawl.dev/v1/scrape \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "URL_HERE", "formats": ["markdown"], "onlyMainContent": true}' \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('data', {}).get('markdown', '') or d.get('markdown', '')
print(f'Fetched: {len(content)} characters')
open('/tmp/vc-product-raw.md', 'w').write(content)
"

フォールバック:Tavily extract(FIRECRAWL_API_KEY が設定されていない場合)

curl -s -X POST https://api.tavily.com/extract \
  -H "Content-Type: application/json" \
  -d "{\"api_key\": \"$TAVILY_API_KEY\", \"urls\": [\"URL_HERE\"]}" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('results', [{}])[0].get('raw_content', '')
print(f'Fetched via Tavily extract: {len(content)} characters')
open('/tmp/vc-product-raw.md', 'w').write(content)
"

ステップ単位のチェックポイント:

python3 -c "
content = open('/tmp/vc-product-raw.md').read()
if len(content) < 200:
    print('ERROR: Page returned fewer than 200 characters.')
else:
    print(f'Content OK: {len(content)} characters')
"

コンテンツが 200 文字未満の場合: 取得を停止します。ユーザーに次のように伝えます:「製品ページから読み取れるコンテンツを取得できませんでした。通常、サイトが JavaScript でレンダリングされており、ブラウザーが必要な場合に発生します。製品の説明を直接貼り付けてください。製品が何をするものか、対象ユーザー、現在の段階を記載してください。」

貼り付けられた説明を product_content として使用し、ステップ 5 に進みます。


ステップ 4:ステージを示すシグナルをローカルで検出する(API 不使用)

分析ステップの前に、取得したマークダウンを正規表現で解析します。

python3 << 'PYEOF'
import re, json

content = open('/tmp/vc-product-raw.md').read().lower()
stage_signals = []

if re.search(r'join\s+(the\s+)?waitlist|sign\s+up\s+for\s+beta|early\s+access|request\s+(an?\s+)?invite|get\s+notified', content):
    stage_signals.append({'signal': 'waitlist or beta CTA', 'stage_hint': 'pre-seed'})

if re.search(r'start\s+(your\s+)?free\s+trial|try\s+(it\s+)?for\s+free|request\s+a?\s+demo|book\s+a?\s+demo|schedule\s+a?\s+demo', content):
    stage_signals.append({'signal': 'free trial or demo CTA', 'stage_hint': 'seed'})

if re.search(r'contact\s+sales|talk\s+to\s+(our\s+)?sales|see\s+pricing|view\s+pricing|plans\s+and\s+pricing', content):
    stage_signals.append({'signal': 'pricing or sales CTA', 'stage_hint': 'series-a'})
if re.search(r'case\s+stud(y|ies)|customer\s+stor(y|ies)|trusted\s+by\s+[\d,]+|used\s+by\s+[\d,]+', content):
    stage_signals.append({'signal': 'case studies or customer count', 'stage_hint': 'series-a'})

if re.search(r'enterprise\s+(plan|pricing|tier)|we.?re\s+hiring|join\s+our\s+team|open\s+positions', content):
    stage_signals.append({'signal': 'enterprise tier or job openings', 'stage_hint': 'series-a-or-b'})

funding_match = re.search(
    r'raised\s+\$[\d,.]+\s*[mk]?|series\s+[abc]\s+round|seed\s+round|(\$[\d,.]+\s*[mk]?\s+(?:seed|series\s+[abc]))',
    content
)
if funding_match:
    stage_signals.append({'signal': f'funding text: {funding_match.group(0).strip()}', 'stage_hint': 'announced'})

if not stage_signals:
    dominant = 'unknown'
elif any(s['stage_hint'] == 'announced' for s in stage_signals):
    dominant = 'announced'
elif any(s['stage_hint'] == 'series-a-or-b' for s in stage_signals):
    dominant = 'series-a'
elif any(s['stage_hint'] == 'series-a' for s in stage_signals):
    dominant = 'series-a'
elif any(s['stage_hint'] == 'seed' for s in stage_signals):
    dominant = 'seed'
else:
    dominant = 'pre-seed'

confidence = 'high' if len(stage_signals) >= 2 else ('medium' if len(stage_signals) == 1 else 'low')

result = {'signals': stage_signals, 'dominant_stage': dominant, 'confidence': confidence}
json.dump(result, open('/tmp/vc-stage-signals.json', 'w'), indent=2)
print(f'Stage: {dominant} ({confidence} confidence) from {len(stage_signals)} signal(s)')
for s in stage_signals:
    print(f'  - {s["signal"]} -> {s["stage_hint"]}')
PYEOF

ステップ 5:製品分析(分類体系、ステージ、ICP)

製品コンテンツとステージシグナルを出力します。

python3 -c "
import json
content = open('/tmp/vc-product-raw.md').read()[:6000]
signals = json.load(open('/tmp/vc-stage-signals.json'))
print('=== PRODUCT PAGE (first 6000 chars) ===')
print(content)
print()
print('=== DETECTED STAGE SIGNALS ===')
print(json.dumps(signals, indent=2))
"

AI への指示: 上記の製品ページのコンテンツを分析します。分類体系、ICP、ステージ分類のみを生成してください。同業企業はまだ生成しないでください(これはステップ 6 のライブ検索で行います)。

/tmp/vc-product-analysis.json に書き込みます。

  • product_name:ページから取得
  • one_line_description:何をするものか、対象者、中心的な価値提案。20 語未満。マーケティング的な表現は使用しないでください。
  • industry_taxonomy:l1(大分類:fintech / healthtech / developer tools / consumer など)、l2(セクター:sales technology / logistics software など)、l3(具体的なニッチ:outbound prospecting / last-mile routing など)。「technology」や「software」のような曖昧なラベルだけでは不十分です。
  • icp:buyer_persona(職種)、company_type、company_size
  • detected_stage:pre-seed / seed / series-a / series-b / unknown
  • stage_confidence:high / medium / low
  • stage_evidence:判断の根拠となった CTA またはページ上のテキストを正確に引用した 1 文。unknown の場合は「明確なシグナルは見つかりませんでした」と記載します。
  • geography_bias:US / Europe / global / unclear
  • comparable_companies:空の配列 [] のままにします。ステップ 6 で入力します。
python3 << 'PYEOF'
import json

analysis = {
    # FILL from your analysis above
    "comparable_companies": []
}

json.dump(analysis, open('/tmp/vc-product-analysis.json', 'w'), indent=2)
print('Product analysis written.')
PYEOF

確認します。

python3 -c "
import json
a = json.load(open('/tmp/vc-product-analysis.json'))
print('Product:', a['product_name'])
print('Industry:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Stage:', a['detected_stage'], '(' + a['stage_confidence'] + ' confidence)')
"

ステップ 5b:検証済みファンドデータセットとのキュレーション済み事前照合

製品の分類体系を、検証済み VC ファンド 25 件のキュレーション済みデータセット(各ファンドのウェブサイトから取得)と照合します。トラック A 向けの、ハルシネーションのないファンド照合結果とシード段階の同業企業を生成します。Tavily のクレジットは消費しません。

タグの対応付けのため、製品分析を出力します。

python3 -c "
import json
a = json.load(open('/tmp/vc-product-analysis.json'))
print('Taxonomy:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Stage:', a['detected_stage'])
print('Geography:', a['geography_bias'])
"

AI への指示: 製品の分類体系を、ファンドデータセットで使用されている標準タグに対応付けます。使用可能なタグ: DevTools、Infrastructure、Open Source、B2B SaaS、AI、Data、FinTech、HealthTech、Enterprise、Consumer、Marketplaces、E-commerce、Crypto、DeepTech、Cybersecurity、Generalist

製品を説明するタグを 2~4 個選択します。detected_stage を Pre-seed、Seed、Series A、Growth のいずれかに対応付けます。geography_bias を US、Europe、India、Global のいずれかに対応付けます。

製品コンテキストを書き込みます。

python3 << 'PYEOF'
import json

# FILL based on taxonomy analysis above
context = {
    "extracted_tags": ["TagA", "TagB"],  # 2-4 tags from the list above
    "stage_hint": "Seed",               # Pre-seed / Seed / Series A / Growth
    "geography_hint": "US"              # US / Europe / India / Global
}
json.dump(context, open('/tmp/vc-product-context.json', 'w'), indent=2)
print('Product context:', context)
PYEOF

埋め込み済みのキュレーションデータセットを使ってスコアリングを実行します。

python3 << 'PYEOF'
import json

context = json.load(open('/tmp/vc-product-context.json'))

VC_FUNDS = [
  {"fund_name":"Y Combinator","thesis":"We provide seed funding for startups. We invest in deeply technical teams building massive companies across all domains.","check_size":"$500k","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","DevTools","AI"],"geography_focus":["Global"],"notable_portfolio":["Stripe","Airbnb","GitLab"],"website":"https://www.ycombinator.com"},
  {"fund_name":"boldstart ventures","thesis":"Day one partner for developer first, crypto, and SaaS founders. We love deeply technical founders solving hard infrastructure problems.","check_size":"$1M - $3M","stage_focus":["Pre-seed","Seed"],"industry_tags":["DevTools","Infrastructure","Crypto"],"geography_focus":["Global","US"],"notable_portfolio":["Snyk","Blockdaemon","Superhuman"],"website":"https://boldstart.vc"},
  {"fund_name":"Heavybit","thesis":"The leading investor in developer-first startups. We help technical founders launch, gain traction, and build enterprise-ready companies.","check_size":"$1M - $5M","stage_focus":["Seed","Series A"],"industry_tags":["DevTools","Infrastructure","Open Source"],"geography_focus":["Global","US"],"notable_portfolio":["PagerDuty","Sanity","Netlify"],"website":"https://www.heavybit.com"},
  {"fund_name":"Amplify Partners","thesis":"We invest in technical founders building the next generation of IT infrastructure, developer tools, and data platforms.","check_size":"$2M - $8M","stage_focus":["Seed","Series A"],"industry_tags":["DevTools","Infrastructure","AI","Data"],"geography_focus":["US"],"notable_portfolio":["Datadog","OCTO","dbt Labs"],"website":"https://www.amplifypartners.com"},
  {"fund_name":"OSS Capital","thesis":"We exclusively back early-stage founders building Commercial Open Source Software (COSS) companies.","check_size":"$500k - $2M","stage_focus":["Pre-seed","Seed","Series A"],"industry_tags":["Open Source","DevTools"],"geography_focus":["Global"],"notable_portfolio":["Cal.com","Appsmith","Hoppscotch"],"website":"https://oss.capital"},
  {"fund_name":"Sequoia Capital","thesis":"We help the daring build legendary companies, from idea to IPO and beyond. Sequoia is an early-stage and growth-stage investor.","check_size":"$1M - $10M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","AI"],"geography_focus":["Global"],"notable_portfolio":["Apple","Google","WhatsApp"],"website":"https://www.sequoiacap.com"},
  {"fund_name":"Andreessen Horowitz (a16z)","thesis":"We invest in software eating the world. We back bold entrepreneurs building the future through technology.","check_size":"$1M - $50M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Crypto","Enterprise","Consumer","AI"],"geography_focus":["Global","US"],"notable_portfolio":["Facebook","Coinbase","Figma"],"website":"https://a16z.com"},
  {"fund_name":"Point Nine Capital","thesis":"We are a seed-stage venture capital firm focused on B2B SaaS and B2B marketplaces globally.","check_size":"$1M - $3M","stage_focus":["Seed"],"industry_tags":["B2B SaaS","Marketplaces"],"geography_focus":["Europe","Global"],"notable_portfolio":["Zendesk","Typeform","Docplanner"],"website":"https://www.pointnine.com"},
  {"fund_name":"Cherry Ventures","thesis":"We champion founders in Europe from their earliest days. We are generalist seed investors.","check_size":"$1M - $4M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","Consumer","B2B SaaS"],"geography_focus":["Europe"],"notable_portfolio":["FlixBus","Auto1 Group","Forto"],"website":"https://www.cherry.vc"},
  {"fund_name":"First Round Capital","thesis":"We are the seed-stage firm that builds the most supportive community for founders.","check_size":"$1M - $4M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","Consumer"],"geography_focus":["US"],"notable_portfolio":["Uber","Notion","Roblox"],"website":"https://firstround.com"},
  {"fund_name":"Bessemer Venture Partners","thesis":"BVP helps entrepreneurs lay strong foundations to build and forge long-standing companies.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","FinTech"],"geography_focus":["Global"],"notable_portfolio":["LinkedIn","Twilio","Shopify"],"website":"https://www.bvp.com"},
  {"fund_name":"Index Ventures","thesis":"We back the best and most ambitious entrepreneurs across all stages to build category-defining businesses.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","FinTech","Consumer","B2B SaaS"],"geography_focus":["Europe","US","Global"],"notable_portfolio":["Dropbox","Slack","Figma"],"website":"https://www.indexventures.com"},
  {"fund_name":"Lightspeed Venture Partners","thesis":"We invest globally in enterprise, consumer, and health founders who are shaping the future.","check_size":"$1M - $25M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Enterprise","Consumer","FinTech"],"geography_focus":["Global"],"notable_portfolio":["Snap","Rippling","MuleSoft"],"website":"https://lsvp.com"},
  {"fund_name":"Accel","thesis":"We partner with exceptional founders from inception through all phases of private company growth.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","B2B SaaS","Consumer","DevTools"],"geography_focus":["Global"],"notable_portfolio":["Facebook","Atlassian","Spotify"],"website":"https://www.accel.com"},
  {"fund_name":"Bain Capital Ventures","thesis":"From seed to growth, we back founders building legendary infrastructure, fintech, application, and commerce companies.","check_size":"$1M - $50M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Infrastructure","FinTech","B2B SaaS"],"geography_focus":["US","Global"],"notable_portfolio":["DocuSign","SendGrid","Redis"],"website":"https://www.baincapitalventures.com"},
  {"fund_name":"Greylock Partners","thesis":"We partner with early-stage founders to build enterprise and consumer software companies that define new categories.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Enterprise","Consumer","Cybersecurity","AI"],"geography_focus":["US"],"notable_portfolio":["Workday","Palo Alto Networks","LinkedIn"],"website":"https://greylock.com"},
  {"fund_name":"Unusual Ventures","thesis":"We provide a breakthrough level of support for early-stage founders building enterprise tech.","check_size":"$1M - $5M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Enterprise","DevTools","B2B SaaS"],"geography_focus":["US"],"notable_portfolio":["Arctic Wolf","Harness","Vivun"],"website":"https://www.unusual.vc"},
  {"fund_name":"Crane Venture Partners","thesis":"We back deep tech and enterprise founders in Europe solving hard problems with data and code.","check_size":"$1M - $4M","stage_focus":["Seed"],"industry_tags":["Enterprise","DeepTech","Data","AI"],"geography_focus":["Europe"],"notable_portfolio":["Onfido","Tessian","Forto"],"website":"https://crane.vc"},
  {"fund_name":"Founder Collective","thesis":"We are a seed-stage venture capital fund, built by founders, for founders. We back weird, wonderful, and wild startups.","check_size":"$500k - $2M","stage_focus":["Seed"],"industry_tags":["Generalist","Consumer","B2B SaaS"],"geography_focus":["US","Global"],"notable_portfolio":["Uber","Airtable","BuzzFeed"],"website":"https://www.foundercollective.com"},
  {"fund_name":"Benchmark","thesis":"We are a partnership of equal partners. We back mission-driven founders at the earliest stages and walk beside them for the long haul.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Generalist","Marketplaces","Enterprise","Consumer"],"geography_focus":["US","Global"],"notable_portfolio":["Uber","Twitter","eBay","Snapchat"],"website":"https://www.benchmark.com"},
  {"fund_name":"Accel India","thesis":"We partner with exceptional founders from inception through all phases of private company growth in the Indian ecosystem.","check_size":"$1M - $15M","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","B2B SaaS","Consumer","FinTech","E-commerce"],"geography_focus":["India"],"notable_portfolio":["Flipkart","Swiggy","Freshworks"],"website":"https://www.accel.com/india"},
  {"fund_name":"Blume Ventures","thesis":"We are a seed and pre-seed venture fund that backs startups with both funding and active mentoring.","check_size":"$500k - $3M","stage_focus":["Pre-seed","Seed"],"industry_tags":["Generalist","B2B SaaS","Consumer","DeepTech","HealthTech"],"geography_focus":["India"],"notable_portfolio":["Unacademy","Purplle","GreyOrange"],"website":"https://blume.vc"},
  {"fund_name":"Elevation Capital","thesis":"We partner with visionary founders in India across early stages to help them build category-defining businesses.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["Generalist","Consumer","FinTech","B2B SaaS","HealthTech"],"geography_focus":["India"],"notable_portfolio":["Paytm","Swiggy","Meesho"],"website":"https://elevationcapital.com"},
  {"fund_name":"Peak XV Partners","thesis":"Formerly Sequoia India & SEA, we partner with founders across early, growth, and public stages to build enduring companies.","check_size":"$1M - $20M+","stage_focus":["Seed","Series A","Growth"],"industry_tags":["Generalist","Consumer","FinTech","B2B SaaS","DevTools","AI"],"geography_focus":["India","South Asia"],"notable_portfolio":["Zomato","Pine Labs","Cred"],"website":"https://www.peakxv.com"},
  {"fund_name":"Nexus Venture Partners","thesis":"We are a US-India venture capital firm backing extraordinary founders building product-first companies.","check_size":"$1M - $10M","stage_focus":["Seed","Series A"],"industry_tags":["B2B SaaS","Enterprise","DevTools","Consumer"],"geography_focus":["India","US"],"notable_portfolio":["Postman","Hasura","Zepto"],"website":"https://nexusvp.com"}
]

STAGE_ORDER = {"Pre-seed": 0, "Seed": 1, "Series A": 2, "Growth": 3}

def score_fund(fund, ctx):
    score = 0
    fund_tags = fund.get("industry_tags", [])
    extracted_tags = ctx.get("extracted_tags", ["Generalist"])
    tag_points = 0
    matched_tags = []
    for tag in extracted_tags:
        if tag in fund_tags:
            tag_points += 5 if tag == "Generalist" else 20
            matched_tags.append(tag)
    tag_points = min(tag_points, 60)
    score += tag_points
    stage_hint = ctx.get("stage_hint")
    fund_stages = fund.get("stage_focus", [])
    if not stage_hint:
        score += 10
    elif fund_stages:
        if stage_hint in fund_stages:
            score += 20
        elif stage_hint in STAGE_ORDER:
            hint_idx = STAGE_ORDER[stage_hint]
            if any(f in STAGE_ORDER and abs(STAGE_ORDER[f] - hint_idx) == 1 for f in fund_stages):
                score += 10
    geo_hint = ctx.get("geography_hint")
    fund_geo = fund.get("geography_focus", ["Global"])
    if not geo_hint or geo_hint == "Global":
        score += 10
    elif fund_geo == ["India"] and geo_hint == "US":
        pass
    elif geo_hint in fund_geo:
        score += 20
    elif "Global" in fund_geo:
        score += 15
    if geo_hint == "US" and "India" in fund_geo and "US" not in fund_geo and "Global" not in fund_geo:
        score = max(0, score - 30)
    if fund_tags and extracted_tags and fund_tags[0] not in extracted_tags and tag_points <= 20:
        score = max(0, score - 15)
    return score, matched_tags

scored = []
for fund in VC_FUNDS:
    score, matched_tags = score_fund(fund, context)
    tier = "High" if score >= 70 else ("Medium" if score >= 40 else "Low")
    scored.append({
        "fund_name": fund["fund_name"],
        "thesis": fund["thesis"],
        "check_size": fund["check_size"],
        "stage_focus": fund["stage_focus"],
        "industry_tags": fund["industry_tags"],
        "geography_focus": fund["geography_focus"],
        "notable_portfolio": fund["notable_portfolio"],
        "website": fund["website"],
        "source": "verified (fund website)",
        "score": score,
        "confidence": tier,
        "matched_tags": matched_tags
    })

scored.sort(key=lambda x: (-x["score"], x["fund_name"]))
relevant = [m for m in scored if m["confidence"] in ("High", "Medium")]

curated_comparables = []
for m in relevant:
    for company in m.get("notable_portfolio", []):
        if company not in curated_comparables:
            curated_comparables.append(company)

output = {
    "high_medium_matches": relevant,
    "curated_comparables": curated_comparables[:6]
}
json.dump(output, open('/tmp/vc-curated-matches.json', 'w'), indent=2)
print(f'Curated matches: {len(relevant)} High/Medium confidence funds')
for m in relevant[:8]:
    print(f'  {m["confidence"]:6} ({m["score"]:3}) {m["fund_name"]}')
print(f'Seed comparables from portfolio: {curated_comparables[:6]}')
PYEOF

Step 6: Tavily を使って類似企業を見つける

Step 5b の厳選ポートフォリオ企業を、類似企業のシードとして読み込みます。

python3 -c "
import json
matches = json.load(open('/tmp/vc-curated-matches.json'))
curated = matches.get('curated_comparables', [])
print(f'Curated portfolio comparables ({len(curated)}): {curated}')
need = max(0, 5 - len(curated))
print(f'Tavily will supplement with up to {need} more')
"

AI の学習知識を使って類似企業を生成しないでください。 上記の厳選ポートフォリオ企業は、検証済みのファンドデータに基づく、ハルシネーションのない類似企業です。Tavily を使って、L3 のニッチに特化した企業を補完します。

python3 << 'PYEOF'
import json, os, urllib.request

analysis = json.load(open('/tmp/vc-product-analysis.json'))
l2 = analysis['industry_taxonomy']['l2']
l3 = analysis['industry_taxonomy']['l3']
tavily_key = os.environ.get('TAVILY_API_KEY', '')

queries = [
    f'"{l3}" startup raised funding venture capital seed series',
    f'"{l2}" companies venture backed funded startup'
]

all_results = []
for query in queries:
    payload = json.dumps({
        "api_key": tavily_key,
        "query": query,
        "search_depth": "advanced",
        "max_results": 8,
        "include_answer": True
    }).encode()

    req = urllib.request.Request(
        'https://api.tavily.com/search',
        data=payload,
        headers={'Content-Type': 'application/json'},
        method='POST'
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            all_results.append({
                'query': query,
                'answer': result.get('answer', ''),
                'results': [
                    {'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:500]}
                    for r in result.get('results', [])
                ]
            })
            print(f'Comparable search: {len(result.get("results", []))} results for "{query[:60]}"')
    except Exception as e:
        print(f'Comparable search FAILED: {e}')
        all_results.append({'query': query, 'answer': '', 'results': [], 'error': str(e)})

json.dump(all_results, open('/tmp/vc-comparable-search.json', 'w'), indent=2)
PYEOF

AI による選定用に結果を出力します。

python3 -c "
import json
results = json.load(open('/tmp/vc-comparable-search.json'))
for r in results:
    print(f'Query: {r[\"query\"]}')
    print(f'Answer: {r.get(\"answer\",\"\")[:400]}')
    for item in r.get('results', []):
        print(f'  - {item[\"title\"]} | {item[\"url\"]}')
        print(f'    {item[\"content\"][:200]}')
    print()
"

AI への指示: /tmp/vc-curated-matches.json の厳選ポートフォリオ企業と、上記の Tavily 検索結果を組み合わせてください。類似企業をちょうど 5 社選びます。厳選ポートフォリオ企業を優先してください(検証済みであり、一致した VC ファンドの実在するポートフォリオ企業です)。必要に応じて、Tavily で見つかった企業を補って 5 社にします。

各類似企業について、以下を記述します。

  • name:企業名
  • similarity_reason:適合する理由を 1 文で説明します(厳選企業の場合は、その企業を支援したファンドに言及し、Tavily で見つかった企業の場合は、スニペットを引用します)
  • source_url:厳選企業の場合はポートフォリオファンドのウェブサイト、検索で見つかった企業の場合は Tavily の検索結果 URL
  • estimated_stage:厳選データまたはスニペットのテキストから記載します。不明な場合は "not in search data" と記載します
  • source_type:"curated_portfolio" または "tavily_discovered"

comparable_companies 配列を使って /tmp/vc-product-analysis.json を更新します。

python3 << 'PYEOF'
import json

analysis = json.load(open('/tmp/vc-product-analysis.json'))

analysis['comparable_companies'] = [
    # FILL 5 companies -- curated_portfolio first, then tavily_discovered
    # Each: {"name": str, "similarity_reason": str, "source_url": str, "estimated_stage": str, "source_type": str}
]

json.dump(analysis, open('/tmp/vc-product-analysis.json', 'w'), indent=2)
print('Comparables written:', ', '.join(c['name'] for c in analysis['comparable_companies']))
PYEOF

検索結果に類似企業が 3 社未満しかない場合: クエリの範囲を広げます。3 回目の検索を実行します:"[l1] startup" funding round venture capital。それでも検索結果が少ない場合は、利用可能な情報で進め、data_quality_flags にその旨を記載します。


Step 7: Track A -- 類似企業に投資した投資家

類似企業ごとに 1 回ずつ、Tavily で 5 回検索します。

python3 << 'PYEOF'
import json, os, urllib.request

analysis = json.load(open('/tmp/vc-product-analysis.json'))
comparables = analysis['comparable_companies']
tavily_key = os.environ.get('TAVILY_API_KEY', '')
all_track_a = []

for comp in comparables:
    company = comp['name']
    query = f'"{company}" investors funding venture capital backed seed series'

    payload = json.dumps({
        "api_key": tavily_key,
        "query": query,
        "search_depth": "advanced",
        "max_results": 5,
        "include_answer": True
    }).encode()

    req = urllib.request.Request(
        'https://api.tavily.com/search',
        data=payload,
        headers={'Content-Type': 'application/json'},
        method='POST'
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            all_track_a.append({
                'comparable_company': company,
                'similarity_reason': comp['similarity_reason'],
                'query': query,
                'answer': result.get('answer', ''),
                'results': result.get('results', [])
            })
            print(f'Track A - {company}: {len(result.get("results", []))} results')
    except Exception as e:
        print(f'Track A - {company}: FAILED ({e})')
        all_track_a.append({
            'comparable_company': company,
            'similarity_reason': comp['similarity_reason'],
            'query': query,
            'answer': '',
            'results': [],
            'error': str(e)
        })

json.dump(all_track_a, open('/tmp/vc-tracka-results.json', 'w'), indent=2)
print(f'Track A complete. Comparables with results: {sum(1 for r in all_track_a if r.get("results"))}')
PYEOF

Track A の検索が 5 回すべて 0 件の場合: クエリの範囲を広げて Step 6 を再実行します。メディアで大きく取り上げられているなど、情報が充実した企業を対象に再試行します。それでも 0 件の場合は Track B のみで進め、data_quality_flags にその旨を記載します。


Step 8: Track B -- この分野に関する投資方針を持つ VC

Step 5 の L2 と L3 の分類を使って、Tavily で 3 回検索します。

python3 << 'PYEOF'
import json, os, urllib.request

analysis = json.load(open('/tmp/vc-product-analysis.json'))
l2 = analysis['industry_taxonomy']['l2']
l3 = analysis['industry_taxonomy']['l3']
stage = analysis['detected_stage']
tavily_key = os.environ.get('TAVILY_API_KEY', '')

queries = [
    {'name': 'thesis_l3', 'query': f'venture capital investment thesis "{l3}" investing 2023 OR 2024 OR 2025'},
    {'name': 'thesis_l2', 'query': f'VC fund "{l2}" investment thesis portfolio companies'},
    {'name': 'stage_space', 'query': f'{stage} investors "{l3}" startup venture capital fund'}
]

all_track_b = []

for q in queries:
    payload = json.dumps({
        "api_key": tavily_key,
        "query": q['query'],
        "search_depth": "advanced",
        "max_results": 7,
        "include_answer": True
    }).encode()

    req = urllib.request.Request(
        'https://api.tavily.com/search',
        data=payload,
        headers={'Content-Type': 'application/json'},
        method='POST'
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            all_track_b.append({
                'query_name': q['name'],
                'query': q['query'],
                'answer': result.get('answer', ''),
                'results': result.get('results', [])
            })
            print(f"Track B - {q['name']}: {len(result.get('results', []))} results")
    except Exception as e:
        print(f"Track B - {q['name']}: FAILED ({e})")
        all_track_b.append({'query_name': q['name'], 'query': q['query'], 'answer': '', 'results': [], 'error': str(e)})

json.dump(all_track_b, open('/tmp/vc-trackb-results.json', 'w'), indent=2)
PYEOF

Track B の検索が 3 回すべて 0 件の場合: Track A の結果のみで進めます。data_quality_flags に「公開検索で投資方針に基づく投資家は見つかりませんでした」と記載します。


ステップ 9:統合 -- すべての VC をランク付けしてスコアリングする

調査データを出力します。

python3 -c "
import json

analysis = json.load(open('/tmp/vc-product-analysis.json'))
track_a = json.load(open('/tmp/vc-tracka-results.json'))
track_b = json.load(open('/tmp/vc-trackb-results.json'))
curated = json.load(open('/tmp/vc-curated-matches.json'))

track_a_summary = []
for item in track_a:
    snippets = [{'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:400]}
                for r in item.get('results', [])[:3]]
    track_a_summary.append({
        'comparable_company': item['comparable_company'],
        'similarity_reason': item['similarity_reason'],
        'answer': item.get('answer', '')[:500],
        'top_results': snippets
    })

track_b_summary = []
for item in track_b:
    snippets = [{'title': r.get('title',''), 'url': r.get('url',''), 'content': r.get('content','')[:400]}
                for r in item.get('results', [])[:4]]
    track_b_summary.append({
        'query_name': item['query_name'],
        'answer': item.get('answer', '')[:500],
        'top_results': snippets
    })

curated_summary = []
for m in curated.get('high_medium_matches', []):
    curated_summary.append({
        'fund_name': m['fund_name'],
        'confidence': m['confidence'],
        'score': m['score'],
        'matched_tags': m['matched_tags'],
        'thesis': m['thesis'],
        'check_size': m['check_size'],
        'stage_focus': m['stage_focus'],
        'notable_portfolio': m['notable_portfolio'],
        'website': m['website'],
        'source': 'verified (fund website)'
    })

print(json.dumps({
    'product': {
        'name': analysis['product_name'],
        'description': analysis['one_line_description'],
        'industry': analysis['industry_taxonomy'],
        'icp': analysis['icp'],
        'stage': analysis['detected_stage'],
        'stage_confidence': analysis['stage_confidence'],
        'geography': analysis['geography_bias']
    },
    'curated_matches': curated_summary,
    'track_a_research': track_a_summary,
    'track_b_research': track_b_summary
}, indent=2))
"

AI への指示 -- ハルシネーションをゼロにするためのルール:

出力のすべてのフィールドは、上記に出力したデータまでたどれる必要があります。ルール:

  1. curated_vcs: curated_matches データをそのまま使用します。これらは事前に検証済みのため、Tavily のエビデンスは不要です。fund_overview は、キュレーションデータの thesis フィールドから取得します。check_size と stage_focus は、キュレーションデータの各フィールドから取得します。これらのファンドについても、学習データの知識から補完してはいけません。
  2. VC 名(トラック A/B): スニペットのテキストまたはタイトルに名前がそのまま記載されているファンドのみを含めます。例外はありません。
  3. evidence_company(トラック A): そのファンドが支援した比較対象企業です。推測ではなく、スニペットのテキストに記載されている必要があります。
  4. thesis_source_title(トラック B): 検索結果に表示されている記事または投稿の正確なタイトルです。
  5. fund_overview(トラック A/B): スニペットのテキストのみから抽出します。最大 2 文です。スニペットにファンドの説明がない場合は、「not found in search data」と記載します。
  6. thesis_summary: スニペットのテキストを忠実に言い換えます。学習データの知識から文脈を追加してはいけません。
  7. check_size(トラック A/B): スニペットのデータのみから取得します。記載がない場合は「not in search data」と記載します。
  8. portfolio_in_space: 検索スニペットに登場する企業のみを記載します。該当する企業がない場合は、「not found in search data」と記載します。
  9. stage_fit_score 1-10: VC が明示しているステージと、プロダクトで検出されたステージが一致しない場合は 3 ポイント減点します。
  10. space_fit_score 1-10: スニペットまたはキュレーションデータから、その VC が L3 ニッチの企業を 2 社以上支援したことが確認できる場合に限り、9~10 点を付けます。
  11. approach_method: cold email/warm intro required/AngelList/application form/Twitter/X DM のいずれかにします。スニペットまたはファンドのウェブサイトから推定します。
  12. outreach_hook: 特定のポートフォリオのシグナル、または投資方針からの引用を明示する必要があります。「トラクションをアピールする」のような一般的なフックは認められません。
  13. エムダッシュは使用しないでください。マーケティング表現は使用しないでください。

/tmp/vc-final-list.json に書き込みます。

  • product_summary:name、one_line_description、industry_l1、industry_l2、industry_l3、detected_stage、comparable_companies_used(名前のみ)
  • curated_vcs:fund_name、confidence("High"/"Medium")、matched_tags、fund_overview(thesis フィールドから取得)、check_size、stage_focus、website、source("verified (fund website)")、stage_fit_score、space_fit_score
  • track_a_vcs:fund_name、evidence_company(必須)、evidence_source_url、stage_focus、check_size、fund_overview、thesis_summary、stage_fit_score、space_fit_score、approach_method
  • track_b_vcs:fund_name、thesis_source_title(必須)、thesis_source_url、stage_focus、check_size、fund_overview、thesis_summary、stage_fit_score、space_fit_score、approach_method
  • top_5_deep_dives:fund_name、track("Curated"/"A"/"B")、fund_overview、why_fit、portfolio_in_space、how_to_approach(30 文字以上)、outreach_hook
  • outreach_hooks:3 つのオブジェクト。各オブジェクトには hook_type、hook_text(2~3 文)、best_for を含めます。
  • data_quality_flags:gaps、missing fields、low-confidence areas
python3 << 'PYEOF'
import json

result = {
    # FILL from synthesis above
    # Must include: product_summary, curated_vcs, track_a_vcs, track_b_vcs, top_5_deep_dives, outreach_hooks, data_quality_flags
}

json.dump(result, open('/tmp/vc-final-list.json', 'w'), indent=2)
print(f'Synthesis written. Curated: {len(result.get("curated_vcs", []))} VCs. Track A: {len(result.get("track_a_vcs", []))} VCs. Track B: {len(result.get("track_b_vcs", []))} VCs.')
PYEOF

ステップ 10:セルフ QA

python3 << 'PYEOF'
import json

result = json.load(open('/tmp/vc-final-list.json'))
failures = []

# Remove Track A VCs missing evidence_company
original_a = len(result.get('track_a_vcs', []))
result['track_a_vcs'] = [v for v in result.get('track_a_vcs', []) if v.get('evidence_company')]
removed_a = original_a - len(result['track_a_vcs'])
if removed_a > 0:
    failures.append(f'Removed {removed_a} Track A VC(s) missing evidence_company')

# Remove Track B VCs missing thesis_source_title
original_b = len(result.get('track_b_vcs', []))
result['track_b_vcs'] = [v for v in result.get('track_b_vcs', []) if v.get('thesis_source_title')]
removed_b = original_b - len(result['track_b_vcs'])
if removed_b > 0:
    failures.append(f'Removed {removed_b} Track B VC(s) missing thesis_source_title')

# Remove deep dives for VCs that were stripped from all tracks
valid_funds = (
    {v['fund_name'] for v in result.get('curated_vcs', [])} |
    {v['fund_name'] for v in result.get('track_a_vcs', [])} |
    {v['fund_name'] for v in result.get('track_b_vcs', [])}
)
original_dives = len(result.get('top_5_deep_dives', []))
result['top_5_deep_dives'] = [d for d in result.get('top_5_deep_dives', []) if d.get('fund_name') in valid_funds]
removed_dives = original_dives - len(result['top_5_deep_dives'])
if removed_dives > 0:
    failures.append(f'Removed {removed_dives} deep dive(s) for funds stripped during QA')

# Check top 5 deep dives
dives = result.get('top_5_deep_dives', [])
if len(dives) < 5:
    failures.append(f'Only {len(dives)} deep dives (expected 5) -- insufficient search data')
for dd in dives:
    if not dd.get('how_to_approach') or len(dd.get('how_to_approach', '')) < 30:
        dd['how_to_approach'] = 'Approach method not determinable from search data. Check the fund website directly for application instructions.'
        failures.append(f"Fixed: '{dd.get('fund_name')}' had missing how_to_approach")
    if not dd.get('fund_overview') or dd.get('fund_overview') == '':
        dd['fund_overview'] = 'not found in search data'

# Check outreach hooks count
if len(result.get('outreach_hooks', [])) != 3:
    failures.append(f"Expected 3 outreach hooks, got {len(result.get('outreach_hooks', []))}")

# Check for em dashes
full_text = json.dumps(result)
if '—' in full_text:
    result = json.loads(full_text.replace('—', '-'))
    failures.append('Fixed: em dash characters replaced with hyphens')

# Check for forbidden words
forbidden = ['powerful', 'robust', 'seamless', 'innovative', 'game-changing', 'streamline', 'leverage', 'transform']
full_text_lower = json.dumps(result).lower()
for word in forbidden:
    if word in full_text_lower:
        failures.append(f"Warning: forbidden word '{word}' found in output -- review before presenting")

# Flag any "not found in search data" entries so user knows coverage is incomplete
not_found_count = json.dumps(result).count('not found in search data')
if not_found_count > 0:
    failures.append(f'INFO: {not_found_count} field(s) marked "not found in search data" -- verify directly before outreach')

if 'data_quality_flags' not in result:
    result['data_quality_flags'] = []
result['data_quality_flags'].extend(failures)

json.dump(result, open('/tmp/vc-final-list.json', 'w'), indent=2)
print(f'QA complete. Issues addressed: {len(failures)}')
for f in failures:
    print(f'  - {f}')
if not failures:
    print('All QA checks passed.')
PYEOF

ステップ 11:出力を保存して提示する

DATE=$(date +%Y-%m-%d)
OUTPUT_FILE="docs/vc-intel/${PRODUCT_SLUG}-${DATE}.md"
mkdir -p docs/vc-intel

最終出力を提示します。

## VC Finder: [product_name]
Date: [today] | Stage: [detected_stage] ([stage_confidence] confidence) | Geography: [geography_bias]

---

### Product Analysis

What it does: [one_line_description]
Industry: [l1] > [l2] > [l3]
Buyer: [buyer_persona] at [company_type], [company_size]
Comparable companies used: [comma-separated list, noting source_type for each]

---

### Curated Matches (Verified)

*Funds matched from a verified dataset of 25 VC funds sourced from fund websites. Zero hallucination -- details come directly from the dataset.*

| Fund | Confidence | Stage Focus | Check Size | Matched Tags |
|---|---|---|---|---|
[one row per curated VC, sorted by confidence then score]

---

### Track A: VCs Who Backed Similar Companies

*These investors have already written a check in this space. Evidence from live Tavily search.*

| Fund | Backed Comparable | Stage Focus | Check Size | Fit Score | Approach |
|---|---|---|---|---|---|
[one row per Track A VC, sorted by space_fit_score descending]

---

### Track B: Thesis-Led Investors

*These investors are actively publishing about this space.*

| Fund | Thesis Source | Stage Focus | Check Size | Fit Score | Approach |
|---|---|---|---|---|---|
[one row per Track B VC, sorted by space_fit_score descending]

---

### Top 5 Deep Dives

#### [N]. [Fund Name] (Track [Curated/A/B])

Overview: [fund_overview -- from dataset or search data only]
Why it fits: [why_fit]
Portfolio in this space: [from dataset or search data, or "not found in search data"]
How to approach: [how_to_approach]
Outreach hook: "[outreach_hook]"

[repeat for all available deep dives]

---

### 3 Outreach Hooks for This Product Type

**1. [hook_type]**
[hook_text]
Best for: [best_for]

[repeat for all 3]

---
Data quality notes: [data_quality_flags, or "None"]
Saved to: docs/vc-intel/[PRODUCT_SLUG]-[DATE].md

一時ファイルをクリーンアップします。

rm -f /tmp/vc-product-raw.md /tmp/vc-stage-signals.json /tmp/vc-product-analysis.json \
      /tmp/vc-product-context.json /tmp/vc-curated-matches.json /tmp/vc-comparable-search.json \
      /tmp/vc-tracka-results.json /tmp/vc-trackb-results.json /tmp/vc-final-list.json

コメント