옵션
집집 Skill 기타 event-prospecting

event-prospecting

browserbase/skills browserbase/skills

컨퍼런스나 행사 연사들의 URL을 입력하면, 연사 목록을 추출하고 사용자의 ICP에 따라 소속 회사를 필터링한 뒤, ICP에 부합하는 회사의 연사들에 대해서만 심층 조사를 수행합니다. 그 결과, 연사별 ‘접촉해야 하는 이유’를 명시한 ‘인물 중심’ HTML 보고서를 생성합니다.

...모든 것을 확장하십시오
0
업데이트 된 시간 2026년 9월 30일

이벤트 잠재 고객 발굴

컨퍼런스 URL을 입력하면 → 영업 담당자(AE)가 접촉해야 할 대상자 목록을 순위별로 제공하며, 각 대상자에 대한 "접촉 이유"를 함께 표시합니다.

필수 조건: BROWSERBASE_API_KEY 환경 변수 및 browse CLI 설치 (npm install -g browse). API 호출에는 browse cloud ...를 사용하고, 자바스크립트가 많이 포함된 연사 페이지의 경우 browse open / browse get markdown을 사용하십시오.

경로 규칙: 모든 Bash 명령어에서 항상 전체 리터럴 경로를 사용하십시오. ~ 또는 $HOME은 사용하지 마십시오(둘 다 "쉘 확장 구문" 승인 요청을 유발합니다). 홈 디렉터리는 한 번만 지정하고 모든 곳에서 동일하게 사용하십시오. 서브에이전트 프롬프트를 구성할 때 {SKILL_DIR}을 전체 리터럴 경로(일반적으로 /Users/jay/skills/skills/event-prospecting)로 대체하십시오.

출력 디렉터리: 모든 이벤트 잠재고객 발굴 결과물은 ~/Desktop/{event_slug}_prospects_{YYYY-MM-DD-HHMM}/로 저장됩니다. 최종 결과물은 index.html (회사별로 그룹화되고 회사 ICP 순으로 정렬된 사람 목록)이며, 대체 보기용으로 companies.html 및 people.html (필터링 가능)과 콜드 아웃바운드 가져오기를 위한 results.csv가 포함됩니다.

중요 — 도구 제한 사항 (주 에이전트 및 모든 하위 에이전트에 적용):

  • 모든 웹 검색: 브라우즈 클라우드 검색을 사용하십시오. WebSearch는 절대로 사용하지 마십시오.
  • 모든 페이지 콘텐츠 추출: node {SKILL_DIR}/scripts/extract_page.mjs ""를 사용하십시오. 이 스크립트는 browse cloud fetch --output을 통해 데이터를 가져오고, 제목 + 메타 태그 + 표시된 본문 텍스트를 파싱하며, 가져오기가 실패하거나 JS로 렌더링된 내용이 부족한 경우 자동으로 browse get markdown으로 대체합니다. 절대 browse cloud fetch | sed 파이프라인을 직접 작성하지 마십시오. WebFetch를 절대 사용하지 마십시오.
  • 모든 연구 결과물: 하위 에이전트는 bash heredoc을 사용하여 기업별 또는 인물별로 하나의 마크다운 파일을 {OUTPUT_DIR}/companies/{slug}.md 또는 {OUTPUT_DIR}/people/{slug}.md에 작성해야 합니다. Write 도구나 python3 -c를 절대 사용하지 마십시오. 두 파일 형식에 대한 자세한 내용은 references/example-research.md를 참조하십시오.
  • 보고서 편집: node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open을 사용하십시오.
  • 하위 담당자는 반드시 Bash 도구만을 사용해야 합니다. 다른 도구는 허용되지 않습니다.
  • 도구 호출 횟수 제한: ICP 분류 = 기업당 1회 호출; 심층 조사 = 기업당 5회 호출; 인물 정보 보강 = 인물당 4회 호출. 적용 세부 사항은 references/workflow.md를 참조하십시오.

중요 — 환각 방지 규칙 (메인 에이전트 및 모든 서브에이전트에 적용):

  • 절대 사이트의 폰트, 프레임워크, 디자인 시스템 또는 타이포그래피를 통해 product_description, 산업 분야 또는 개인의 role_reason을 추론해서는 안 됩니다. 이는 외관상의 요소일 뿐, 회사가 무엇을 판매하는지 또는 그 사람이 무엇을 하는지에 대해서는 아무런 정보를 제공하지 않습니다.
  • 절대 사용자의 ICP가 대상의 설명에 반영되지 않도록 하십시오. 대상이 무엇을 하는지 알 수 없는 경우, ‘알 수 없음(Unknown)’ 이라고 기재하십시오 — 대상에게 사용자의 ICP를 일률적으로 대입하지 마십시오.
  • product_description은 extract_page.mjs 출력물에서 특정 문구를 인용하거나 의역해야 합니다. TITLE/META/OG/HEADINGS/BODY 중 어느 곳에서도 식별 가능한 제품 설명이 나오지 않으면 'Unknown'이라고 기재하십시오 — 홈페이지 콘텐츠에 접근할 수 없으므로 icp_fit_score는 3으로 제한하십시오.
  • 사용자의 hook은 브라우즈 클라우드 검색 결과(팟캐스트 제목, 블로그 헤드라인, GitHub 저장소, 강연 초록)에서 특정 결과를 인용하거나 의역해야 합니다. 지난 6개월 동안 공개된 신호가 없는 경우, 이벤트 컨텍스트(해당 이벤트에서의 강연 제목)로 대체하십시오.

중요 — 권한 요청 창을 최소화하십시오:

  • 하위 에이전트는 연쇄된 heredoc을 사용하여 모든 파일 쓰기 작업을 단일 Bash 호출로 묶어야 합니다. 하나의 Bash 호출 = 하나의 권한 요청.
  • && 연쇄를 사용하여 모든 검색 및 모든 가져오기를 단일 Bash 호출로 묶어야 합니다.

파이프라인 개요

다음 10단계를 순서대로 따르십시오. 단계를 건너뛰거나 순서를 변경하지 마십시오.

  1. 설정 — 출력 디렉터리 + 초기화
  2. 프로필 불러오기 — profiles/{user_slug}.json 읽기
  3. 재구성 — 이벤트 플랫폼 감지
  4. 사용자 추출 — people.jsonl
  5. 기업별 그룹화 — seed_companies.txt
  6. ICP 선별 — 신속한 기업 수준 점수 산정 (기업당 1회 호출)
  7. 필터링 — icp_fit_score가 --icp-threshold 이상인 기업
  8. 심층 조사 — ICP 적합성에 대한 전체 계획→조사→종합 분석
  9. 발표자 정보 보강 — 사용자에게 질문: ICP 적합성만 포함(기본값) 또는 모든 발표자
  10. 보고서 생성 — HTML + CSV, 브라우저에서 열기

사용자는 /event-prospecting 와 같은 URL로 스킬을 호출합니다. 해당 호출 메시지에서 EVENT_URL을 파싱합니다. 기본값: DEPTH=deep, ICP_THRESHOLD=6. USER_SLUG (ICP 프로필)은 1단계에서 로컬에 존재하는 프로필 파일을 기반으로 자동으로 해결됩니다. 내장된 기본 프로필은 없습니다. 사용자에게 URL 확인을 요청하지 마십시오. 사용자는 이미 URL을 제공했습니다.

0단계: 출력 디렉터리 설정

사용자가 제공한 URL에서 출력 디렉터리를 도출합니다. 어떤 이벤트 이름도 하드코딩하지 마십시오.

# EVENT_URL은 호출 메시지(사용자가 `/event-prospecting` 뒤에 입력한 내용)에서 가져왔습니다.
EVENT_SLUG=$(node -e 'const h = new URL(process.argv[1]).hostname.replace(/^www\./,""); console.log(h.split(".")[0])' "$EVENT_URL")
TIMESTAMP=$(date +%Y-%m-%d-%H%M)
OUTPUT_DIR=/Users/jay/Desktop/${EVENT_SLUG}_prospects_${TIMESTAMP}
mkdir -p "$OUTPUT_DIR/companies" "$OUTPUT_DIR/people"

~ 나 $HOME을 절대 사용하지 말고, 전체 리터럴 홈 경로를 사용하십시오. 모든 서브에이전트 프롬프트에 {OUTPUT_DIR}을 전체 리터럴 경로로 전달하십시오.

1단계: 사용자 프로필 불러오기

프로필은 ICP 분류 및 심층 조사 점수 산정의 기준이 되는 ICP를 정의합니다. {SKILL_DIR}/profiles/{user_slug}.json에서 불러오세요(모든 GTM 스킬에서 상호 교환 가능 — company-research와 동일한 형식). example.json은 템플릿일 뿐 실제 프로필이 아니므로 절대 사용하지 마세요.

{SKILL_DIR}/profiles/ 외부의 프로필을절대 검색하지 마십시오 — 다른 스킬의 디렉터리에 절대 접근하지 마십시오. 다른 곳에서 프로필이 필요한 경우, 사용자가 직접 복사해야 합니다.

해결 순서:

  1. 사용자가 --user-company 옵션을 사용하여 호출한 경우, 해당 슬러그를 사용합니다.
  2. 그렇지 않은 경우, example.json을 제외한 profiles/*.json을 나열합니다. 프로필이 정확히 하나만 존재하면 이를 사용하며(사용자에게 어떤 프로필인지 알려줌), 여러 개가 존재하면 사용자에게(일반 채팅을 통해) 어떤 프로필을 사용할지 묻습니다.
  3. 프로필이 하나도 없는 경우, 명확하게 오류 메시지를 표시하고 사용자에게 프로필을 생성하도록 안내합니다( profiles/example.json을 profiles/.json으로 복사하여 내용을 입력하거나, 프로필을 자동으로 생성하는 company-research 스킬을 실행하도록 안내).
PROFILES=$(ls {SKILL_DIR}/profiles/*.json 2>/dev/null | xargs -n1 basename | sed 's/\.json$//' | grep -v '^example$')
COUNT=$(echo "$PROFILES" | grep -c .)

if [ -z "$USER_SLUG" ]; then
  if [ "$COUNT" -eq 0 ]; then
    echo "{SKILL_DIR}/profiles/ 디렉터리에 프로필이 없습니다. profiles/example.json 파일을 profiles/.json으로 복사하여 내용을 입력하거나, company-research 스킬을 실행하여 프로필을 생성하십시오."
    exit 1
  elif [ "$COUNT" -eq 1 ]; then
    USER_SLUG=$PROFILES
    echo "사용 가능한 유일한 프로필을 사용합니다: ${USER_SLUG}"
  else
    echo "여러 개의 프로필이 발견되었습니다:"
    echo "$PROFILES" | sed 's/^/  - /'
    echo "하나를 선택하려면 --user-company  옵션을 사용하여 다시 실행하십시오."
    exit 1
  fi
fi

test -f {SKILL_DIR}/profiles/${USER_SLUG}.json || {
  echo "프로필을 찾을 수 없음: profiles/${USER_SLUG}.json"
  exit 1
}
cat {SKILL_DIR}/profiles/${USER_SLUG}.json

이 프로필에는 company, product, icp_description, existing_customers가 포함됩니다. 이 항목들은 이후의 모든 하위 에이전트 프롬프트에 그대로 포함됩니다.

2단계: 정찰

이벤트 플랫폼과 추출 전략을 탐지합니다. 단일 명령어:

node {SKILL_DIR}/scripts/recon.mjs {EVENT_URL} {OUTPUT_DIR}

{OUTPUT_DIR}/recon.json 파일에 플랫폼, 전략 및 (Next.js의 경우) nextDataPaths 정보를 기록합니다. 플랫폼 목록 및 탐지 우선순위에 대해서는 references/event-platforms.md를 참조하십시오.

예상 결과:

  • Stripe Sessions 클래스 (Next.js): platform: "next-data", 경로 1~3개
  • Sessionize: platform: "sessionize"
  • Lu.ma / Eventbrite: platform: "luma" | "eventbrite"
  • 기타: platform: "custom", strategy: "markdown" (최선의 노력을 다하는 대체 처리)

3단계: 사람 정보 추출

node {SKILL_DIR}/scripts/extract_event.mjs {OUTPUT_DIR} --user-company {USER_SLUG}

recon.json을 읽고, 플랫폼별 추출기로 전달한 후, people.jsonl (한 줄에 연사 한 명)과 seed_companies.txt (중복 제거된 기업 목록)를 작성합니다.

--user-company 플래그는 호스트 조직의 직원(예: Stripe가 주최하는 이벤트에서는 Stripe 직원)과 사용자의 소속 직원을 연사 목록에서 제외합니다. 이들은 잠재 고객이 아니기 때문입니다.

출력 결과를 확인합니다:

wc -l {OUTPUT_DIR}/people.jsonl {OUTPUT_DIR}/seed_companies.txt
head -3 {OUTPUT_DIR}/people.jsonl

people.jsonl 파일이 비어 있거나 10줄 미만인 경우, recon이 잘못된 플랫폼을 선택한 것입니다. references/event-platforms.md를 확인하고 전략을 조정한 후 다시 실행하십시오.

4단계: 회사별로 그룹화

extract_event.mjs는 이미 seed_companies.txt 파일을 출력합니다(한 줄에 한 회사, 중복 제거 및 정렬됨). 이 단계는 참고용입니다. 분산 처리하기 전에 개수가 타당한지 확인하십시오:

wc -l {OUTPUT_DIR}/seed_companies.txt

예상치: 연사 수의 대략 0.4~0.6배 (대부분의 이벤트는 기업당 평균 약 2명의 연사가 참여하며, 일부 기업은 5명 이상을, 많은 기업은 1명을 보냅니다).

5단계: ICP 선별

신속 처리 — 기업당 하나의 도구 호출만 수행하며, 심층 조사는 진행하지 않습니다. seed_companies.txt에 있는 모든 기업에 대해 사용자의 ICP를 기준으로 점수를 매기고, companies/{slug}.md에 간략한 선별 스텁을 작성합니다. icp_fit_score가 --icp-threshold (기본값 6) 이상인 기업은 7단계의 심층 조사로 진행되며, 나머지는 선별 요약본으로 남습니다.

배치 패턴: seed_companies.txt를 약 10개씩 배치로 나누고, 단일 에이전트 배치 내에서 N개의 하위 에이전트를 분산 배치합니다(하나의 메시지에 여러 에이전트 도구 호출 포함). 각 하위 에이전트는 references/workflow.md → “ICP 선별” 섹션의 프롬프트를 실행합니다. 상한선: 기업당 1회의 도구 호출 (홈페이지에 대한 extract_page.mjs만 실행), # browse 호출 시 N/1 주석 패턴을 통해 강제 적용.

# 배치 파일 생성: 각 배치 행은 "이름|추정된_홈페이지|슬러그" 형식입니다.
# extract_event.mjs는 회사 이름만 출력하므로(URL 없음), 슬러그를 생성하고
# https://{공백 없는 슬러그}.com을 표준 홈페이지로 추정합니다. 트라이아지 서브에이전트는
# product_description: "알 수 없음 — 홈페이지 콘텐츠에 접근할 수 없음"을 기록할 수 있으며
# 추정한 URL에서 404 오류가 발생하면 점수를 3으로 제한할 수 있습니다. 이는
# workflow.md에 문서화된 대체 처리 방식입니다(ICP 트라이아지 프롬프트의 규칙 3). URL을 찾기 위해 실제 브라우징 클라우드 검색을 실행하면
# 기업당 1회 호출이라는 엄격한 제한을 초과하게 됩니다.
node -e '
const fs = require("fs");
const slugify = (s) => (s || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
const seed = fs.readFileSync("{OUTPUT_DIR}/seed_companies.txt", "utf-8").split("\n").filter(Boolean);
const lines = seed.map(c => {
  const slug = slugify(c);
  const guessedHost = c.toLowerCase().replace(/[^a-z0-9]/g, "");
  return `${c}|https://${guessedHost}.com|${slug}`;
});
fs.writeFileSync("{OUTPUT_DIR}/_seed_with_urls.txt", lines.join("\n") + "\n");
'

# 약 10개 기업 단위로 분할
split -l 10 {OUTPUT_DIR}/_seed_with_urls.txt {OUTPUT_DIR}/_batch_triage_

# 배치 수 → 파견할 하위 에이전트 수 (메시지당 최대 6개; 나머지는 두 번째 파로 처리)
ls {OUTPUT_DIR}/_batch_triage_* | wc -l

그런 다음 단일 메시지 내에서 배치당 에이전트 호출 1건을 배정합니다(최대 6개까지 병렬 처리; 첫 번째 파동이 완료된 후 나머지 처리를 위한 후속 파동). 각 에이전트는 references/workflow.md → "ICP Triage"에서 프롬프트를 가져오며, 전송 전에 다음 내용을 대체합니다:

  • {SKILL_DIR} → 스킬의 전체 리터럴 경로 (예: /Users/jay/skills/skills/event-prospecting)
  • {OUTPUT_DIR} → 출력 경로의 전체 리터럴 경로
  • {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION} → 로드된 프로필에서 가져옴
  • {EVENT_NAME} → recon.json의 .title
  • {COMPANY_LIST} → 배치 파일의 내용 (예: cat {OUTPUT_DIR}/_batch_triage_aa)
  • {TOTAL} → 이 배치의 줄 수 ( # browse 호출 시 N/{TOTAL}로 대체)

에이전트 배정 (기본 구조, 한 메시지에 배치당 반복):

Agent(
  description: "ICP triage batch aa",
  prompt: ,
  subagent_type: "general-purpose"
)
에이전트(
  description: "ICP 분류 배치 ab",
  prompt: ,
  subagent_type: "general-purpose"
)
... 메시지당 최대 6개

모든 하위 에이전트가 반환된 후, seed_companies.txt에 있는 모든 회사에 해당하는 companies/{slug}.md 파일이 있는지 확인합니다:

ls {OUTPUT_DIR}/companies/*.md | wc -l
# `wc -l {OUTPUT_DIR}/seed_companies.txt`와 일치해야 함

배치 파일을 정리합니다: rm {OUTPUT_DIR}/_batch_triage_*.

6단계: ICP 임계값으로 필터링

각 companies/*.md 파일의 프론트매터를 읽고, icp_fit_score가 6 이상 (또는 --icp-threshold로 지정된 값)인 항목만 유지합니다. 남아 있는 회사 슬러그를 {OUTPUT_DIR}/icp_fits.txt에 기록합니다:

THRESHOLD=6   # --icp-threshold 플래그에서 설정된 값
for f in {OUTPUT_DIR}/companies/*.md; do
  score=$(awk '/^icp_fit_score:/{print $2; exit}' "$f")
  if [ -n "$score" ] && [ "$score" -ge "$THRESHOLD" ]; then
    basename "$f" .md
  fi
done > {OUTPUT_DIR}/icp_fits.txt

wc -l {OUTPUT_DIR}/icp_fits.txt

예상치: seed_companies.txt의 20~40%. 생존율이 10% 미만이면 임계값이 너무 높거나 ICP 설명이 너무 좁을 수 있으므로 사용자에게 경고를 표시하십시오.

7단계: 심층 조사

전체 계획→연구→ICP에 적합한 기업에 대해서만 종합 분석 수행. 엄격한 제한: 기업당 최대 5회 도구 호출 (홈페이지 추출 + 2~3회 하위 질문 검색 + 1~2회 보충 자료 수집). 서브에이전트는 기존 companies/{slug}.md 선별 스텁을 더 풍부한 심층 조사 버전으로 덮어씁니다(프론트매터 triage_only: false).

배포 패턴: icp_fits.txt를 약 5개씩(심층 모드 기본값) 배치로 나누고, 배치당 하나의 에이전트를 단일 메시지로 분산 배치합니다(메시지당 최대 6개의 에이전트). 각 에이전트는 references/workflow.md의 “심층 조사” 프롬프트를 받으며, 다음 값으로 대체됩니다:

  • {SKILL_DIR}, {OUTPUT_DIR}, {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION}
  • {EVENT_NAME} ( recon.json 의 .title에서 가져옴), {EVENT_CONTEXT} (트랙/주제, 이벤트 홈페이지에서 수동으로 추론됨)
  • {COMPANY_LIST} → 배치 파일의 내용 (각 행: slug|website)
# 각 트라이아지 스텁의 프론트매터를 읽어 {company-slug|website} 쌍을 생성
while read slug; do
  website=$(awk '/^website:/{print $2; exit}' {OUTPUT_DIR}/companies/${slug}.md)
  echo "${slug}|${website}"
done < {OUTPUT_DIR}/icp_fits.txt > {OUTPUT_DIR}/_deep_targets.txt

# 약 5개 기업 단위로 배치 분할 (심층 모드)
split -l 5 {OUTPUT_DIR}/_deep_targets.txt {OUTPUT_DIR}/_batch_deep_
ls {OUTPUT_DIR}/_batch_deep_* | wc -l

에이전트 배정 (기본 구조, 한 메시지에 배치별로 반복):

Agent(
  description: "심층 연구 배치 aa",
  prompt: ,
  subagent_type: "일반 목적"
)
Agent(
  description: "심층 연구 배치 ab",
  prompt: ,
  subagent_type: "general-purpose"
)
... 메시지당 최대 6개까지; 첫 번째 배치의 결과가 반환된 후 두 번째 배치 실행

모든 하위 에이전트가 반환된 후, 심층 연구 파일이 존재하고 triage_only: false로 설정되어 있는지 확인합니다:

grep -l "triage_only: false" {OUTPUT_DIR}/companies/*.md | wc -l
# 결과는 wc -l icp_fits.txt와 같아야 함

8단계: 연사 정보 보강

1인당: LinkedIn URL, 최근 활동 내역(팟캐스트 / 블로그 / 강연 / GitHub / X)을 수집하고, people/{slug}.md 파일을 작성합니다. 최대 제한: 1인당 도구 호출 4회, 세 가지 경로:

  1. 클라우드 검색 "{이름} {회사} linkedin" (항상)
  2. 브라우즈 클라우드 검색 "{이름} 팟캐스트 OR 강연 OR 블로그 2026" (심층+)
  3. 브라우즈 클라우드 검색 "{이름} github" (더 심층)
  4. 브라우즈 클라우드 검색 "{이름} site:x.com OR site:twitter.com" (더 심층, 최선을 다함)

빠른 모드: 8단계를 완전히 건너뜁니다. 심층 모드: 레인 1~2. 더 심층 모드: 레인 1~4.

8a단계 — 사용자에게 확인: 정보 보강 범위

처리를 시작하기 전에 두 가지 후보 수를 계산하고 사용자에게 선택하도록 요청합니다. 기본값은 ICP-fit만 적용하는 것입니다(더 빠르고, 비용이 적게 들며, 대부분의 사용자가 원하는 방식). 모든 화자의 정보를 보강하는 기능은 선택 사항이며, 이는 보강되는 인원 수에 따라 비용이 선형적으로 증가하기 때문입니다.

TOTAL=$(wc -l < {OUTPUT_DIR}/people.jsonl)
ICP_FITS=$(node -e '
const fs = require("fs");
const fits = new Set(fs.readFileSync("{OUTPUT_DIR}/icp_fits.txt", "utf-8").split("\n").filter(Boolean));
const slug2name = {};
for (const slug of fits) {
  const md = fs.readFileSync(`{OUTPUT_DIR}/companies/${slug}.md`, "utf-8");
  const m = md.match(/^company_name:\s*(.+)$/m);
  if (m) slug2name[slug] = m[1].trim();
}
const want = new Set(Object.values(slug2name).map(s => s.toLowerCase()));
const ppl = fs.readFileSync("{OUTPUT_DIR}/people.jsonl", "utf-8").split("\n").filter(Boolean).map(JSON.parse);
console.log(ppl.filter(p => p.company && want.has(p.company.toLowerCase())).length);
')

# 1인당 레인 수: 2(얕은) 또는 4(더 깊은) — {DEPTH}와 일치
LANES=2   # 더 깊게 분석하려면 4
echo "ICP 적합: ${ICP_FITS} 연사 × ${LANES} = $((ICP_FITS * LANES)) 통화"
echo "전체:      ${TOTAL} 연사 × ${LANES} = $((TOTAL * LANES)) 통화"

그런 다음 AskUserQuestion을 통해 질문합니다 — 각 옵션에 정량화된 비용이 명시된 명확한 두 가지 선택지:

AskUserQuestion(questions: [
  {
    question: "어떤 화자를 보강할까요?",
    header: "강화 범위",
    multiSelect: false,
    options: [
      { label: "ICP FITS만", description: "${ICP_FITS} 스피커, ~$((ICP_FITS * LANES)) 호출 (권장)" },
      { label: "ICP FITS만", description: "${ICP_FITS} 명의 연사, ~$((ICP_FITS * LANES)) 건의 통화" }
    ]
  }
])

선택한 범위를 ENRICH_SCOPE=icp_fits 또는 ENRICH_SCOPE=all로 저장하십시오. 사용자가 "모든 스피커"를 선택했고 TOTAL × LANES > 600인 경우, 경고를 표시하고 다시 한 번 확인을 요청하십시오. 이는 수백 번의 도구 호출이 포함된 10분 이상의 실행 시간이 소요되는 작업입니다.

8b단계 — 필터링 및 일괄 처리

# ENRICH_SCOPE를 기반으로 _people_to_enrich.jsonl 생성
if [ "$ENRICH_SCOPE" = "all" ]; then
  cp {OUTPUT_DIR}/people.jsonl {OUTPUT_DIR}/_people_to_enrich.jsonl
else
  node -e '
const fs = require("fs");
const fits = new Set(fs.readFileSync("{OUTPUT_DIR}/icp_fits.txt", "utf-8").split("\n").filter(Boolean));
const slug2name = {};
for (const slug of fits) {
  const md = fs.readFileSync(`{OUTPUT_DIR}/companies/${slug}.md`, "utf-8");
  const m = md.match(/^company_name:\s*(.+)$/m);
  if (m) slug2name[slug] = m[1].trim();
}
const wantNames = new Set(Object.values(slug2name).map(s => s.toLowerCase()));
const lines = fs.readFileSync("{OUTPUT_DIR}/people.jsonl", "utf-8").split("\n").filter(Boolean);
const keep = lines.filter(l => {
  const p = JSON.parse(l);
  return p.company && wantNames.has(p.company.toLowerCase());
});
fs.writeFileSync("{OUTPUT_DIR}/_people_to_enrich.jsonl", keep.join("\n") + "\n");
console.error(`${lines.length}명의 연사 중 ${keep.length}명을 보강 중`);
'
fi

# 약 5명 단위로 분할
split -l 5 {OUTPUT_DIR}/_people_to_enrich.jsonl {OUTPUT_DIR}/_batch_people_

그런 다음 단일 메시지 내에서, references/workflow.md → "Person Enrichment"에 있는 프롬프트를 사용하여 배치당 하나의 에이전트 호출(메시지당 최대 6개)을 전송합니다. 각 하위 에이전트의 프롬프트에는 다음이 포함되어야 합니다:

  • {SKILL_DIR}, {OUTPUT_DIR}, {DEPTH} (deep | deeper)
  • {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION}
  • {EVENT_NAME} ( recon.json의 .title에서 가져옴)
  • {LANES} → deep 모드일 경우 2, deeper 모드일 경우 4 ( N/{LANES} 형태의 # browse 호출에 대입됨)
  • {PEOPLE_BATCH} → _batch_people_aa 의 내용 (각 행은 people.jsonl의 JSON 레코드)

에이전트 디스패치 (기본 구조, 한 메시지에 배치별로 반복):

Agent(
  description: "Person enrichment batch aa",
  prompt: ,
  subagent_type: "general-purpose"
)
Agent(
  description: "Person enrichment batch ab",
  prompt: ,
  subagent_type: "general-purpose"
)
... 메시지당 최대 6개

모든 하위 에이전트가 반환된 후, 사람 관련 파일이 존재하는지 확인합니다:

ls {OUTPUT_DIR}/people/*.md | wc -l
# 결과는 wc -l _people_to_enrich.jsonl과 같아야 함

9단계: 보고서 생성

한 번의 명령어로 회사별로 그룹화된 HTML 색인, 대체 보기 및 CSV를 생성합니다:

node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open

이 명령을 실행하면 다음 파일이 생성됩니다:

  • {OUTPUT_DIR}/index.html — 회사별로 그룹화되고, 회사별 ICP 점수 순으로 정렬된 인물 목록 (브라우저에서 열림)
  • {OUTPUT_DIR}/people.html — 필터링 가능한 연사 목록 (대체 보기)
  • {OUTPUT_DIR}/companies.html — ICP 순위에 따라 정렬된 기업 표 및 참석자 목록
  • {OUTPUT_DIR}/results.csv — 콜드 아웃바운드 영업에 바로 활용 가능한 스프레드시트

그런 다음 채팅에 요약 내용을 표시합니다:

## 이벤트 잠재고객 발굴 완료 — {이벤트 이름}

- **추출된 총 연사 수**: {count}
- **고유 기업 수**: {count}
- **ICP 적합 기업 (점수 ≥ {threshold})**: {count}
- **연사 정보 보강 완료**: {count}
- **점수 분포** (기업):
  - 높은 적합도 (8-10): {count}
  - 부분적 적합도 (5-7): {count}
  - 부적합 (1-4): {count}
- **브라우저에서 보고서 열기**: {OUTPUT_DIR}/index.html

기업별 ICP 점수 순으로 정렬된 마크다운 표 형식으로 상위 5개의 인물 카드를 표시한 후, 다음을 제안합니다:

  • --icp-threshold 값을 조정하고 6~9단계를 다시 실행하세요
  • CSV 파일을 CRM으로 내보내기
GitHub에서 보기
---
name: event-prospecting
description: Takes a conference or event speakers URL, extracts the people, filters their companies against the user's ICP, and deep-researches only the speakers at ICP-fit companies. Outputs a person-first HTML report with a 'why reach out' rationale per person.
license: MIT
---

# Event Prospecting

Take a conference URL → get a ranked list of people the AE should talk to, with a "why reach out" rationale per person.

**Required**: `BROWSERBASE_API_KEY` env var and the `browse` CLI installed (`npm install -g browse`). Use `browse cloud ...` for API calls and `browse open` / `browse get markdown` for JS-heavy speaker pages.

**Path rules**: Always use the full literal path in all Bash commands — NOT `~` or `$HOME` (both trigger "shell expansion syntax" approval prompts). Resolve the home directory once and use it everywhere. When constructing subagent prompts, replace `{SKILL_DIR}` with the full literal path (typically `/Users/jay/skills/skills/event-prospecting`).

**Output directory**: All event prospecting output goes to `~/Desktop/{event_slug}_prospects_{YYYY-MM-DD-HHMM}/`. Final deliverable is `index.html` (people grouped by company, ranked by company ICP), with `companies.html` and `people.html` (filterable) as alternate views, plus `results.csv` for cold-outbound import.

**CRITICAL — Tool restrictions (applies to main agent AND all subagents)**:
- All web searches: use `browse cloud search`. NEVER use WebSearch.
- All page content extraction: use `node {SKILL_DIR}/scripts/extract_page.mjs "<url>"`. This script fetches via `browse cloud fetch --output`, parses title + meta tags + visible body text, and automatically falls back to `browse get markdown` when fetch fails or returns thin JS-rendered content. NEVER hand-roll a `browse cloud fetch | sed` pipeline. NEVER use WebFetch.
- All research output: subagents write **one markdown file per company OR per person** to `{OUTPUT_DIR}/companies/{slug}.md` or `{OUTPUT_DIR}/people/{slug}.md` using bash heredoc. NEVER use the Write tool or `python3 -c`. See `references/example-research.md` for both file formats.
- Report compilation: use `node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open`.
- **Subagents must use ONLY the Bash tool. No other tools allowed.**
- **HARD TOOL-CALL CAPS**: ICP triage = 1 call/company; deep research = 5 calls/company; person enrichment = 4 calls/person. See `references/workflow.md` for enforcement detail.

**CRITICAL — Anti-hallucination rules (applies to main agent AND all subagents)**:
- NEVER infer `product_description`, `industry`, or a person's `role_reason` from a site's fonts, framework, design system, or typography. These are cosmetic and say nothing about what the company sells or what the person does.
- NEVER let the user's own ICP leak into a target's description. If you don't know what the target does, write `Unknown` — do not pattern-match them onto the ICP.
- `product_description` MUST quote or paraphrase a specific phrase from `extract_page.mjs` output. If none of TITLE/META/OG/HEADINGS/BODY yield a recognizable product statement, write `Unknown — homepage content not accessible` and cap `icp_fit_score` at 3.
- A person's `hook` MUST quote or paraphrase a specific finding from a `browse cloud search` result (podcast title, blog headline, GitHub repo, talk abstract). If no public signal exists in the last 6 months, fall back to event-context (their talk title at this event).

**CRITICAL — Minimize permission prompts**:
- Subagents MUST batch ALL file writes into a SINGLE Bash call using chained heredocs. One Bash call = one permission prompt.
- Batch ALL searches and ALL fetches into single Bash calls using `&&` chaining.

## Pipeline Overview

Follow these 10 steps in order. Do not skip steps or reorder.

0. **Setup** — output dir + clean slate
1. **Load profile** — read `profiles/{user_slug}.json`
2. **Recon** — detect event platform
3. **Extract people** — `people.jsonl`
4. **Group by company** — `seed_companies.txt`
5. **ICP triage** — fast company-level scoring (1 call/company)
6. **Filter** — companies with `icp_fit_score >= --icp-threshold`
7. **Deep research** — full Plan→Research→Synthesize on ICP fits
8. **Enrich speakers** — ask user: ICP-fit only (default) or all speakers
9. **Compile report** — HTML + CSV, open in browser

The user invokes the skill with a URL like `/event-prospecting <URL>`. Parse `EVENT_URL` from that invocation message. Defaults: `DEPTH=deep`, `ICP_THRESHOLD=6`. The `USER_SLUG` (ICP profile) is auto-resolved in Step 1 from whatever profile files exist locally — there is no built-in default profile. Do NOT ask the user to confirm the URL — they already gave you it.

---

## Step 0: Setup Output Directory

Derive the output directory from the URL the user gave you. Do NOT hardcode any event name.

```bash
# EVENT_URL came from the invocation message (whatever the user typed after `/event-prospecting`)
EVENT_SLUG=$(node -e 'const h = new URL(process.argv[1]).hostname.replace(/^www\./,""); console.log(h.split(".")[0])' "$EVENT_URL")
TIMESTAMP=$(date +%Y-%m-%d-%H%M)
OUTPUT_DIR=/Users/jay/Desktop/${EVENT_SLUG}_prospects_${TIMESTAMP}
mkdir -p "$OUTPUT_DIR/companies" "$OUTPUT_DIR/people"
```

Use the full literal home path — never `~` or `$HOME`. Pass `{OUTPUT_DIR}` as the full literal path to all subagent prompts.

## Step 1: Load User Profile

The profile defines the ICP that ICP triage and deep research score against. Load from `{SKILL_DIR}/profiles/{user_slug}.json` (interchangeable across all GTM skills — same shape as company-research). `example.json` is a template, not a real profile — never use it.

**DO NOT look outside `{SKILL_DIR}/profiles/`** for profiles — never reach into other skills' directories. If a profile is needed elsewhere, the user copies it explicitly.

**Resolution order**:
1. If the user invoked with `--user-company <slug>`, use that slug.
2. Else, list `profiles/*.json` excluding `example.json`. If exactly one profile exists, use it (and tell the user which one). If multiple exist, ask the user (plain chat) which one.
3. If zero profiles exist, **fail loudly** and instruct the user to create one (copy `profiles/example.json` to `profiles/<your_slug>.json` and fill it in, or run the company-research skill which builds one automatically).

```bash
PROFILES=$(ls {SKILL_DIR}/profiles/*.json 2>/dev/null | xargs -n1 basename | sed 's/\.json$//' | grep -v '^example$')
COUNT=$(echo "$PROFILES" | grep -c .)

if [ -z "$USER_SLUG" ]; then
  if [ "$COUNT" -eq 0 ]; then
    echo "No profiles found in {SKILL_DIR}/profiles/. Copy profiles/example.json to profiles/<your_slug>.json and fill it in, or run the company-research skill to build one."
    exit 1
  elif [ "$COUNT" -eq 1 ]; then
    USER_SLUG=$PROFILES
    echo "Using the only profile available: ${USER_SLUG}"
  else
    echo "Multiple profiles found:"
    echo "$PROFILES" | sed 's/^/  - /'
    echo "Re-invoke with --user-company <slug> to pick one."
    exit 1
  fi
fi

test -f {SKILL_DIR}/profiles/${USER_SLUG}.json || {
  echo "Profile not found: profiles/${USER_SLUG}.json"
  exit 1
}
cat {SKILL_DIR}/profiles/${USER_SLUG}.json
```

The profile yields: `company`, `product`, `icp_description`, `existing_customers`. These get embedded verbatim in every subagent prompt downstream.

## Step 2: Recon

Detect the event platform and extraction strategy. One command:

```bash
node {SKILL_DIR}/scripts/recon.mjs {EVENT_URL} {OUTPUT_DIR}
```

Writes `{OUTPUT_DIR}/recon.json` with `platform`, `strategy`, and (for Next.js) `nextDataPaths`. See `references/event-platforms.md` for the platform catalog and detection priority.

Expected outcomes:
- Stripe Sessions class (Next.js): `platform: "next-data"`, 1-3 paths
- Sessionize: `platform: "sessionize"`
- Lu.ma / Eventbrite: `platform: "luma" | "eventbrite"`
- Anything else: `platform: "custom"`, `strategy: "markdown"` (best-effort fallback)

## Step 3: Extract People

```bash
node {SKILL_DIR}/scripts/extract_event.mjs {OUTPUT_DIR} --user-company {USER_SLUG}
```

Reads `recon.json`, dispatches to the platform-specific extractor, writes `people.jsonl` (one speaker per line) and `seed_companies.txt` (deduped companies).

The `--user-company` flag also drops the host-org's own employees (a Stripe-hosted event drops Stripe employees) and the user's own employees from the speaker list — those aren't prospects.

Sanity-check the output:
```bash
wc -l {OUTPUT_DIR}/people.jsonl {OUTPUT_DIR}/seed_companies.txt
head -3 {OUTPUT_DIR}/people.jsonl
```

If `people.jsonl` is empty or under ~10 lines, recon picked the wrong platform — see `references/event-platforms.md` and re-run with adjusted strategy.

## Step 4: Group by Company

`extract_event.mjs` emits `seed_companies.txt` already (one company per line, deduped, sorted). This step is informational — verify the count looks reasonable before fanning out:

```bash
wc -l {OUTPUT_DIR}/seed_companies.txt
```

Expected: roughly 0.4-0.6× the speaker count (most events have ~2 speakers per company on average, some companies send 5+, many send 1).

## Step 5: ICP Triage

**Fast pass — one tool call per company, no deep research.** Score every company in `seed_companies.txt` against the user's ICP and write a thin triage stub to `companies/{slug}.md`. Companies with `icp_fit_score >= --icp-threshold` (default 6) advance to Step 7's deep research; the rest stay as triage stubs.

**Dispatch pattern**: split `seed_companies.txt` into batches of ~10 and fan out N subagents in a SINGLE Agent batch (multiple Agent tool calls in one message). Each subagent runs the prompt from `references/workflow.md` → "ICP Triage" section. Hard cap: **1 tool call per company** (just `extract_page.mjs` on the homepage), enforced via the `# browse call N/1` comment pattern.

```bash
# Build batch files: each batch line is "name|guessed_homepage|slug".
# extract_event.mjs only emits company NAMES (no URLs), so we slugify and guess
# https://{slug-without-spaces}.com as the canonical homepage. The triage subagent
# is allowed to write product_description: "Unknown — homepage content not accessible"
# and cap score at 3 if the guessed URL 404s — that's the documented fallback in
# workflow.md (rule 3 of the ICP Triage prompt). Burning a real browse cloud search to
# discover the URL would bust the 1-call-per-company HARD CAP.
node -e '
const fs = require("fs");
const slugify = (s) => (s || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
const seed = fs.readFileSync("{OUTPUT_DIR}/seed_companies.txt", "utf-8").split("\n").filter(Boolean);
const lines = seed.map(c => {
  const slug = slugify(c);
  const guessedHost = c.toLowerCase().replace(/[^a-z0-9]/g, "");
  return `${c}|https://${guessedHost}.com|${slug}`;
});
fs.writeFileSync("{OUTPUT_DIR}/_seed_with_urls.txt", lines.join("\n") + "\n");
'

# Split into ~10-company batches
split -l 10 {OUTPUT_DIR}/_seed_with_urls.txt {OUTPUT_DIR}/_batch_triage_

# Count batches → number of subagents to dispatch (cap at 6 per message; second wave for the rest)
ls {OUTPUT_DIR}/_batch_triage_* | wc -l
```

Then in a single message, dispatch one Agent call per batch (up to 6 in parallel; subsequent waves after the first returns). Each Agent gets the prompt from `references/workflow.md` → "ICP Triage" with these substitutions before sending:
- `{SKILL_DIR}` → full literal skill path (e.g. `/Users/jay/skills/skills/event-prospecting`)
- `{OUTPUT_DIR}` → full literal output path
- `{USER_COMPANY}`, `{USER_PRODUCT}`, `{ICP_DESCRIPTION}` → from the loaded profile
- `{EVENT_NAME}` → `recon.json` `.title`
- `{COMPANY_LIST}` → contents of the batch file (e.g. `cat {OUTPUT_DIR}/_batch_triage_aa`)
- `{TOTAL}` → number of lines in this batch (substitute into `# browse call N/{TOTAL}`)

**Agent dispatch (skeleton, repeat per batch in one message)**:

```
Agent(
  description: "ICP triage batch aa",
  prompt: <ICP Triage prompt from workflow.md with all placeholders substituted>,
  subagent_type: "general-purpose"
)
Agent(
  description: "ICP triage batch ab",
  prompt: <same prompt template, COMPANY_LIST swapped to batch ab>,
  subagent_type: "general-purpose"
)
... up to 6 per message
```

After all subagents return, verify every company in `seed_companies.txt` has a corresponding `companies/{slug}.md`:

```bash
ls {OUTPUT_DIR}/companies/*.md | wc -l
# Should equal `wc -l {OUTPUT_DIR}/seed_companies.txt`
```

Clean up the batch files: `rm {OUTPUT_DIR}/_batch_triage_*`.

## Step 6: Filter by ICP Threshold

Read each `companies/*.md` frontmatter, keep those with `icp_fit_score >= 6` (or whatever `--icp-threshold` is). Write the surviving company slugs to `{OUTPUT_DIR}/icp_fits.txt`:

```bash
THRESHOLD=6   # from --icp-threshold flag
for f in {OUTPUT_DIR}/companies/*.md; do
  score=$(awk '/^icp_fit_score:/{print $2; exit}' "$f")
  if [ -n "$score" ] && [ "$score" -ge "$THRESHOLD" ]; then
    basename "$f" .md
  fi
done > {OUTPUT_DIR}/icp_fits.txt

wc -l {OUTPUT_DIR}/icp_fits.txt
```

Expected: 20-40% of `seed_companies.txt`. If the survival rate is < 10%, the threshold may be too high or the ICP description too narrow — surface a warning to the user.

## Step 7: Deep Research

Full Plan→Research→Synthesize on ICP-fit companies only. Hard cap: **5 tool calls per company** (homepage extract + 2-3 sub-question searches + 1-2 supplementary fetches). Subagents OVERWRITE the existing `companies/{slug}.md` triage stub with the richer deep-research version (frontmatter `triage_only: false`).

**Dispatch pattern**: split `icp_fits.txt` into batches of ~5 (deep mode default) and fan out one Agent per batch in a SINGLE message (up to 6 Agents per message). Each Agent gets the prompt from `references/workflow.md` → "Deep Research" with these substitutions:
- `{SKILL_DIR}`, `{OUTPUT_DIR}`, `{USER_COMPANY}`, `{USER_PRODUCT}`, `{ICP_DESCRIPTION}`
- `{EVENT_NAME}` (from `recon.json` `.title`), `{EVENT_CONTEXT}` (track / topic, manually inferred from the event homepage)
- `{COMPANY_LIST}` → contents of the batch file (each line `slug|website`)

```bash
# Build {company-slug|website} pairs by reading frontmatter from each triage stub
while read slug; do
  website=$(awk '/^website:/{print $2; exit}' {OUTPUT_DIR}/companies/${slug}.md)
  echo "${slug}|${website}"
done < {OUTPUT_DIR}/icp_fits.txt > {OUTPUT_DIR}/_deep_targets.txt

# Split into ~5-company batches (deep mode)
split -l 5 {OUTPUT_DIR}/_deep_targets.txt {OUTPUT_DIR}/_batch_deep_
ls {OUTPUT_DIR}/_batch_deep_* | wc -l
```

**Agent dispatch (skeleton, repeat per batch in one message)**:

```
Agent(
  description: "Deep research batch aa",
  prompt: <Deep Research prompt from workflow.md with all placeholders substituted; COMPANY_LIST = cat _batch_deep_aa>,
  subagent_type: "general-purpose"
)
Agent(
  description: "Deep research batch ab",
  prompt: <same template, COMPANY_LIST = cat _batch_deep_ab>,
  subagent_type: "general-purpose"
)
... up to 6 per message; second wave after the first returns
```

After all subagents return, verify the deep-research files exist and have `triage_only: false`:

```bash
grep -l "triage_only: false" {OUTPUT_DIR}/companies/*.md | wc -l
# Should equal wc -l icp_fits.txt
```

## Step 8: Enrich Speakers

Per person: harvest LinkedIn URL, recent activity (podcast / blog / talk / GitHub / X), and write `people/{slug}.md`. Hard cap: **4 tool calls per person**, three lanes:

1. `browse cloud search "{name} {company} linkedin"` (always)
2. `browse cloud search "{name} podcast OR talk OR blog 2026"` (deep+)
3. `browse cloud search "{name} github"` (deeper)
4. `browse cloud search "{name} site:x.com OR site:twitter.com"` (deeper, best-effort)

Quick mode: skip Step 8 entirely. Deep mode: lanes 1-2. Deeper mode: lanes 1-4.

### Step 8a — Ask the user: scope of enrichment

Before dispatching, compute the two candidate counts and ask the user to choose. The default is **ICP-fit only** (faster, cheaper, what most users want); enriching every speaker is opt-in because cost scales linearly with people enriched.

```bash
TOTAL=$(wc -l < {OUTPUT_DIR}/people.jsonl)
ICP_FITS=$(node -e '
const fs = require("fs");
const fits = new Set(fs.readFileSync("{OUTPUT_DIR}/icp_fits.txt", "utf-8").split("\n").filter(Boolean));
const slug2name = {};
for (const slug of fits) {
  const md = fs.readFileSync(`{OUTPUT_DIR}/companies/${slug}.md`, "utf-8");
  const m = md.match(/^company_name:\s*(.+)$/m);
  if (m) slug2name[slug] = m[1].trim();
}
const want = new Set(Object.values(slug2name).map(s => s.toLowerCase()));
const ppl = fs.readFileSync("{OUTPUT_DIR}/people.jsonl","utf-8").split("\n").filter(Boolean).map(JSON.parse);
console.log(ppl.filter(p => p.company && want.has(p.company.toLowerCase())).length);
')

# Lanes per person: 2 (deep) or 4 (deeper) — match {DEPTH}
LANES=2   # or 4 for deeper
echo "ICP fits: ${ICP_FITS} speakers × ${LANES} = $((ICP_FITS * LANES)) calls"
echo "All:      ${TOTAL} speakers × ${LANES} = $((TOTAL * LANES)) calls"
```

Then ask via `AskUserQuestion` — clean two-option choice with the quantified cost on each:

```
AskUserQuestion(questions: [
  {
    question: "Enrich which speakers?",
    header: "Enrichment scope",
    multiSelect: false,
    options: [
      { label: "ICP fits only", description: "${ICP_FITS} speakers, ~$((ICP_FITS * LANES)) calls (recommended)" },
      { label: "All speakers", description: "${TOTAL} speakers, ~$((TOTAL * LANES)) calls" }
    ]
  }
])
```

Save the chosen scope as `ENRICH_SCOPE=icp_fits` or `ENRICH_SCOPE=all`. If the user picks "All speakers" and `TOTAL × LANES > 600`, print a warning and ask once more — that's a 10+ minute run with hundreds of tool calls.

### Step 8b — Filter and batch

```bash
# Build _people_to_enrich.jsonl based on ENRICH_SCOPE
if [ "$ENRICH_SCOPE" = "all" ]; then
  cp {OUTPUT_DIR}/people.jsonl {OUTPUT_DIR}/_people_to_enrich.jsonl
else
  node -e '
const fs = require("fs");
const fits = new Set(fs.readFileSync("{OUTPUT_DIR}/icp_fits.txt", "utf-8").split("\n").filter(Boolean));
const slug2name = {};
for (const slug of fits) {
  const md = fs.readFileSync(`{OUTPUT_DIR}/companies/${slug}.md`, "utf-8");
  const m = md.match(/^company_name:\s*(.+)$/m);
  if (m) slug2name[slug] = m[1].trim();
}
const wantNames = new Set(Object.values(slug2name).map(s => s.toLowerCase()));
const lines = fs.readFileSync("{OUTPUT_DIR}/people.jsonl", "utf-8").split("\n").filter(Boolean);
const keep = lines.filter(l => {
  const p = JSON.parse(l);
  return p.company && wantNames.has(p.company.toLowerCase());
});
fs.writeFileSync("{OUTPUT_DIR}/_people_to_enrich.jsonl", keep.join("\n") + "\n");
console.error(`Enriching ${keep.length} of ${lines.length} speakers`);
'
fi

# Split into ~5-person batches
split -l 5 {OUTPUT_DIR}/_people_to_enrich.jsonl {OUTPUT_DIR}/_batch_people_
```

Then in a single message, dispatch one Agent call per batch (up to 6 per message) with the prompt from `references/workflow.md` → "Person Enrichment". Each subagent's prompt should include:
- `{SKILL_DIR}`, `{OUTPUT_DIR}`, `{DEPTH}` (`deep` | `deeper`)
- `{USER_COMPANY}`, `{USER_PRODUCT}`, `{ICP_DESCRIPTION}`
- `{EVENT_NAME}` (from `recon.json` `.title`)
- `{LANES}` → `2` for deep mode, `4` for deeper mode (substituted into `# browse call N/{LANES}`)
- `{PEOPLE_BATCH}` → contents of `_batch_people_aa` (each line a JSON record from `people.jsonl`)

**Agent dispatch (skeleton, repeat per batch in one message)**:

```
Agent(
  description: "Person enrichment batch aa",
  prompt: <Person Enrichment prompt from workflow.md with all placeholders substituted; PEOPLE_BATCH = cat _batch_people_aa>,
  subagent_type: "general-purpose"
)
Agent(
  description: "Person enrichment batch ab",
  prompt: <same template, PEOPLE_BATCH = cat _batch_people_ab>,
  subagent_type: "general-purpose"
)
... up to 6 per message
```

After all subagents return, verify the people files exist:

```bash
ls {OUTPUT_DIR}/people/*.md | wc -l
# Should equal wc -l _people_to_enrich.jsonl
```

## Step 9: Compile Report

Generate the company-grouped HTML index, alternate views, and CSV in one command:

```bash
node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open
```

This generates:
- `{OUTPUT_DIR}/index.html` — people grouped by company, ranked by company ICP score (opens in browser)
- `{OUTPUT_DIR}/people.html` — filterable speaker list (alternate view)
- `{OUTPUT_DIR}/companies.html` — ICP-ranked company table with attendees
- `{OUTPUT_DIR}/results.csv` — cold-outbound-ready spreadsheet

Then present a summary in chat:

```
## Event Prospecting Complete — {Event Name}

- **Total speakers extracted**: {count}
- **Unique companies**: {count}
- **ICP fits (score ≥ {threshold})**: {count}
- **Speakers enriched**: {count}
- **Score distribution** (companies):
  - Strong fit (8-10): {count}
  - Partial fit (5-7): {count}
  - Weak fit (1-4): {count}
- **Report opened in browser**: {OUTPUT_DIR}/index.html
```

Show the **top 5 people cards** as a markdown table sorted by company ICP score, then offer to:
- Adjust `--icp-threshold` and re-run Steps 6-9
- Export the CSV to a CRM

event-prospecting 설치

스킬 파일을 다운로드한 후 .claude/skills/ 디렉터리에 압축을 풀어주세요.

ZIP 다운로드

저장소를 클론하고 스킬 파일을 프로젝트에 복사하세요.

git clone https://github.com/browserbase/skills/tree/main/skills/event-prospecting # Copy SKILL.md to your .claude/skills/ directory

복사 복사
빠른 설정: 스킬 폴더를 .claude/skills/로 복사하세요. Claude가 해당 스킬을 자동으로 감지하여 사용합니다.
저장소 browserbase/skills

관련 스킬

multica-creating-agents
업데이트 된 시간 2026년 8월 12일
tilemaps
업데이트 된 시간 2026년 8월 4일
v4-new-features
업데이트 된 시간 2026년 8월 4일
pixijs-application
업데이트 된 시간 2026년 8월 4일
OR