event-prospecting
browserbase/skills
컨퍼런스나 행사 연사들의 URL을 입력하면, 연사 목록을 추출하고 사용자의 ICP에 따라 소속 회사를 필터링한 뒤, ICP에 부합하는 회사의 연사들에 대해서만 심층 조사를 수행합니다. 그 결과, 연사별 ‘접촉해야 하는 이유’를 명시한 ‘인물 중심’ HTML 보고서를 생성합니다.
...모든 것을 확장하십시오이벤트 잠재 고객 발굴
컨퍼런스 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단계를 순서대로 따르십시오. 단계를 건너뛰거나 순서를 변경하지 마십시오.
- 설정 — 출력 디렉터리 + 초기화
- 프로필 불러오기 —
profiles/{user_slug}.json읽기 - 재구성 — 이벤트 플랫폼 감지
- 사용자 추출 —
people.jsonl - 기업별 그룹화 —
seed_companies.txt - ICP 선별 — 신속한 기업 수준 점수 산정 (기업당 1회 호출)
- 필터링 —
icp_fit_score가--icp-threshold 이상인기업 - 심층 조사 — ICP 적합성에 대한 전체 계획→조사→종합 분석
- 발표자 정보 보강 — 사용자에게 질문: ICP 적합성만 포함(기본값) 또는 모든 발표자
- 보고서 생성 — 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/ 외부의 프로필을절대 검색하지 마십시오 — 다른 스킬의 디렉터리에 절대 접근하지 마십시오. 다른 곳에서 프로필이 필요한 경우, 사용자가 직접 복사해야 합니다.
해결 순서:
- 사용자가
--user-company옵션을 사용하여 호출한 경우, 해당 슬러그를 사용합니다. - 그렇지 않은 경우,
example.json을제외한profiles/*.json을나열합니다. 프로필이 정확히 하나만 존재하면 이를 사용하며(사용자에게 어떤 프로필인지 알려줌), 여러 개가 존재하면 사용자에게(일반 채팅을 통해) 어떤 프로필을 사용할지 묻습니다. - 프로필이 하나도 없는 경우, 명확하게 오류 메시지를 표시하고 사용자에게 프로필을 생성하도록 안내합니다(
profiles/example.json을profiles/복사하여 내용을 입력하거나, 프로필을 자동으로 생성하는 company-research 스킬을 실행하도록 안내)..json으로
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회, 세 가지 경로:
클라우드 검색 "{이름} {회사} linkedin"(항상)브라우즈 클라우드 검색 "{이름} 팟캐스트 OR 강연 OR 블로그 2026"(심층+)브라우즈 클라우드 검색 "{이름} github"(더 심층)브라우즈 클라우드 검색 "{이름} 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으로 내보내기
---
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
복사





집
