关于 event-prospecting
event-prospecting 是一项 Claude 技能,可将会议网址整理为销售联系对象的排序名单,并说明联系每个人的理由。它提取参会者、按 ICP 评估其公司、补充符合条件的讲者信息,最后生成 HTML 视图和 CSV。
主要功能
- 01识别活动平台并提取讲者
- 02按公司归类讲者
- 03依据 ICP 初筛公司
- 04研究符合条件的公司并补充讲者信息
- 05汇总生成排序 HTML 视图和 CSV
适用场景
- 01为销售拓客识别会议参会者
- 02根据所属公司的 ICP 匹配度确定讲者优先级
- 03为外呼营销准备活动潜客数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ browserbase/ skills --skill event-prospecting安装后在 Claude Code 中输入/event-prospecting确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitignoreLICENSE.txtprofiles/example.jsonreferences/event-platforms.mdexample-research.mdreport-template.htmlresearch-patterns.mdworkflow.mdscripts/compile_report.mjsextract_event.mjsextract_page.mjspackage.jsonrecon.mjsscripts/__fixtures__/stripe-snapshot.json详细介绍
活动寻客
提供会议 URL → 获取 AE 应联系的人员排名列表,并为每个人提供“联系理由”。
必需:BROWSERBASE_API_KEY 环境变量,以及已安装的 browse CLI(npm install -g browse)。API 调用请使用 browse cloud ...;对于由 JS 驱动的演讲者页面,请使用 browse open / browse get markdown。
路径规则:所有 Bash 命令中始终使用完整的字面路径,不要使用 ~ 或 $HOME(二者都会触发“shell expansion syntax”审批提示)。只解析一次主目录,并在所有地方使用该路径。构造子 Agent 提示词时,将 {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。
关键——工具限制(适用于主 Agent 和所有子 Agent):
- 所有网页搜索:使用
browse cloud search。绝不要使用 WebSearch。 - 所有页面内容提取:使用
node {SKILL_DIR}/scripts/extract_page.mjs "<url>"。此脚本通过browse cloud fetch --output获取内容,解析标题、meta 标签和可见正文文本,并在获取失败或返回内容过少的 JS 渲染页面时自动回退到browse get markdown。绝不要自行拼接browse cloud fetch | sed管道。绝不要使用 WebFetch。 - 所有研究输出:子 Agent 使用 bash heredoc,将每家公司或每个人写入一个 Markdown 文件,路径分别为
{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。 - 子 Agent 只能使用 Bash 工具。不得使用其他工具。
- 严格限制工具调用次数:ICP 初筛 = 每家公司 1 次;深入研究 = 每家公司 5 次;人员信息补充 = 每人 4 次。执行细则请参阅
references/workflow.md。
关键——防止幻觉规则(适用于主 Agent 和所有子 Agent):
- 绝不要根据网站的字体、框架、设计系统或排版推断
product_description、industry或某人的role_reason。这些都是外观设计元素,与公司的销售内容或个人的工作内容无关。 - 绝不要让用户自己的 ICP 混入目标对象的描述。如果不清楚目标对象的业务,写
Unknown——不要将其生搬硬套到 ICP 中。 product_description必须引用或转述extract_page.mjs输出中的具体措辞。如果 TITLE/META/OG/HEADINGS/BODY 中均没有可识别的产品描述,写Unknown — homepage content not accessible,并将icp_fit_score最高设为 3。- 某人的
hook必须引用或转述browse cloud search结果中的具体发现(播客标题、博客标题、GitHub 仓库、演讲摘要)。如果最近 6 个月没有公开信号,则回退到活动背景信息(此人在本次活动上的演讲标题)。
关键——减少权限提示:
- 子 Agent 必须将所有文件写入操作合并到一次 Bash 调用中,使用链式 heredoc。一次 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> 的 URL 调用该技能。从该调用消息中解析 EVENT_URL。默认值:DEPTH=deep、ICP_THRESHOLD=6。USER_SLUG(ICP 资料)会在步骤 1 中根据本地现有的资料文件自动解析——没有内置的默认资料。不要要求用户确认 URL——他们已经提供了。
步骤 0:设置输出目录
根据用户提供的 URL 推导输出目录。不要硬编码任何活动名称。
# 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"
使用完整的字面 home 路径——绝不要使用 ~ 或 $HOME。在所有子 Agent 提示词中,将 {OUTPUT_DIR} 作为完整的字面路径传入。
步骤 1:加载用户资料
资料定义了 ICP 初筛和深度研究所依据的 ICP。请从 {SKILL_DIR}/profiles/{user_slug}.json 加载(可在所有 GTM 技能间通用——结构与 company-research 相同)。example.json 是模板,不是真实资料——绝不要使用它。
不要在 {SKILL_DIR}/profiles/ 以外查找资料——绝不要访问其他技能的目录。如果其他地方需要资料,用户必须自行复制。
解析顺序:
- 如果用户调用时使用了
--user-company <slug>,则使用该 slug。 - 否则,列出
profiles/*.json,排除example.json。如果恰好存在一份资料,则使用它(并告知用户使用了哪一份)。如果存在多份,则在普通聊天中询问用户选择哪一份。 - 如果不存在任何资料,则明确报错并指示用户创建一份(将
profiles/example.json复制为profiles/<your_slug>.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 "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
资料包含:company、product、icp_description、existing_customers。这些内容会原样嵌入下游的每个子 Agent 提示词中。
步骤 2:侦察
检测活动平台和提取策略。执行一条命令:
node {SKILL_DIR}/scripts/recon.mjs {EVENT_URL} {OUTPUT_DIR}
写入 {OUTPUT_DIR}/recon.json,其中包含 platform、strategy,以及(对于 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 行,说明侦察选择了错误的平台——请参阅 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 初筛
快速筛查——每家公司调用一次工具,不做深入研究。 根据用户的 ICP 评估 seed_companies.txt 中的每家公司,并将简要初筛结果写入 companies/{slug}.md。icp_fit_score >= --icp-threshold(默认值为 6)的公司进入步骤 7,进行深入研究;其余公司保留为初筛结果。
分派模式:将 seed_companies.txt 拆分为每批约 10 家公司,并在一次 Agent 批次中分派 N 个子 Agent(在一条消息中调用多个 Agent 工具)。每个子 Agent 使用 references/workflow.md →「ICP Triage」部分的提示词。硬性上限:每家公司调用 1 次工具(仅对首页运行 extract_page.mjs),通过 # browse call N/1 注释模式强制执行。
# 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
然后在一条消息中,每批分派一个 Agent 调用(最多 6 个并行;第一批返回后再分派后续批次)。每个 Agent 使用 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 call N/{TOTAL}中)
Agent 分派(骨架,每批在一条消息中重复一次):
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
所有子 Agent 返回后,确认 seed_companies.txt 中的每家公司都有对应的 companies/{slug}.md:
ls {OUTPUT_DIR}/companies/*.md | wc -l
# Should equal `wc -l {OUTPUT_DIR}/seed_companies.txt`
清理批次文件:rm {OUTPUT_DIR}/_batch_triage_*。
步骤 6:按 ICP 阈值筛选
读取每个 companies/*.md 的 frontmatter,保留 icp_fit_score >= 6(或指定的 --icp-threshold 值)的公司。将符合条件公司的 slug 写入 {OUTPUT_DIR}/icp_fits.txt:
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
预期保留 seed_companies.txt 中 20-40% 的公司。如果保留率低于 10%,阈值可能过高,或 ICP 描述过于狭窄——向用户提示警告。
步骤 7:深入研究
仅对符合 ICP 的公司执行完整的规划→研究→综合流程。硬性上限:每家公司调用 5 次工具(提取首页 + 2-3 次子问题搜索 + 1-2 次补充抓取)。子 Agent 将用更详尽的深入研究版本覆盖现有的 companies/{slug}.md 初筛文件(frontmatter 中的 triage_only: false)。
分派模式:将 icp_fits.txt 拆分为每批约 5 家公司(深入模式的默认值),并在一条消息中每批分派一个 Agent(每条消息最多 6 个 Agent)。每个 Agent 使用 references/workflow.md →「Deep Research」部分的提示词,并替换以下内容:
{SKILL_DIR}、{OUTPUT_DIR}、{USER_COMPANY}、{USER_PRODUCT}、{ICP_DESCRIPTION}{EVENT_NAME}(来自recon.json中的.title)、{EVENT_CONTEXT}(赛道 / 主题,根据活动首页人工推断){COMPANY_LIST}→ 批次文件内容(每行格式为slug|website)
# 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 分派(骨架,每批在一条消息中重复一次):
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
所有子 Agent 返回后,确认深入研究文件已存在且包含 triage_only: false:
grep -l "triage_only: false" {OUTPUT_DIR}/companies/*.md | wc -l
# Should equal wc -l icp_fits.txt
步骤 8:补充演讲者信息
对每个人:收集 LinkedIn URL、近期动态(播客 / 博客 / 演讲 / GitHub / X),并写入 people/{slug}.md。硬性上限:每人调用 4 次工具,分为三条路径:
browse cloud search "{name} {company} linkedin"(始终执行)browse cloud search "{name} podcast OR talk OR blog 2026"(深入模式及以上)browse cloud search "{name} github"(更深入模式)browse cloud search "{name} site:x.com OR site:twitter.com"(更深入模式,尽力而为)
快速模式:完全跳过步骤 8。深入模式:执行路径 1-2。更深入模式:执行路径 1-4。
步骤 8a — 询问用户:丰富数据的范围
派发前,先计算两个候选人数并让用户选择。默认仅针对 符合 ICP 的人选(更快、更便宜,也是大多数用户的选择);丰富所有演讲者的信息需要用户主动选择,因为成本会随丰富信息的人数线性增长。
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"
然后通过 AskUserQuestion 询问——提供两个清晰的选项,并注明各自的费用:
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" }
]
}
])
将所选范围保存为 ENRICH_SCOPE=icp_fits 或 ENRICH_SCOPE=all。如果用户选择“所有演讲者”,且 TOTAL × LANES > 600,请打印警告并再次询问——这会是一次耗时 10 分钟以上、涉及数百次工具调用的运行。
步骤 8b — 筛选并分批
# 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_
然后在一条消息中,每批派发一个 Agent 调用(每条消息最多 6 个),并使用 references/workflow.md →“人员信息丰富”中的提示词。每个子 Agent 的提示词应包含:
{SKILL_DIR}、{OUTPUT_DIR}、{DEPTH}(deep|deeper){USER_COMPANY}、{USER_PRODUCT}、{ICP_DESCRIPTION}{EVENT_NAME}(取自recon.json的.title){LANES}→ 深度模式为2,更深模式为4(替换# browse call N/{LANES}中的值){PEOPLE_BATCH}→_batch_people_aa的内容(每行是一条来自people.jsonl的 JSON 记录)
Agent 派发(骨架,在一条消息中按批次重复):
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
所有子 Agent 返回后,验证人员文件是否存在:
ls {OUTPUT_DIR}/people/*.md | wc -l
# Should equal 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— 可用于冷外联的电子表格
然后在聊天中提供摘要:
## 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
以按公司 ICP 评分排序的 Markdown 表格展示 排名前 5 的人员卡片,然后询问用户是否要:
- 调整
--icp-threshold并重新运行步骤 6-9 - 将 CSV 导出到 CRM