npx skills add ...
npx skills add browserbase/skills --skill event-prospecting
Event prospecting skill. Takes a conference / event speakers URL, extracts the people, filters their companies against the user's ICP, then deep-researches only the speakers at ICP-fit companies. Outputs a person-first HTML report where each card answers "why should the AE talk to this person?" with all public links and a one-click DM opener. Use when the user wants to: (1) find leads at a specific conference, (2) prep for an event, (3) research event speakers, (4) build a target list from a sponsor/exhibitor page, (5) scrape conference speakers and rank by ICP fit. Triggers: "find leads at {event}", "research speakers at", "prospect this conference", "stripe sessions leads", "ai engineer summit prospects", "event prospecting", "scrape conference speakers", "who should I meet at".
npx skills add browserbase/skills --skill 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):
browse cloud search. NEVER use WebSearch.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.{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.node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open.references/workflow.md for enforcement detail.CRITICAL — Anti-hallucination rules (applies to main agent AND all subagents):
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.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.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:
&& chaining.Follow these 10 steps in order. Do not skip steps or reorder.
profiles/{user_slug}.jsonpeople.jsonlseed_companies.txticp_fit_score >= --icp-thresholdThe 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.
Derive the output directory from the URL the user gave you. Do NOT hardcode any event name.
Use the full literal home path — never ~ or $HOME. Pass {OUTPUT_DIR} as the full literal path to all subagent prompts.
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:
--user-company <slug>, use that slug.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.profiles/example.json to profiles/<your_slug>.json and fill it in, or run the company-research skill which builds one automatically).The profile yields: company, product, icp_description, existing_customers. These get embedded verbatim in every subagent prompt downstream.
Detect the event platform and extraction strategy. One command:
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:
platform: "next-data", 1-3 pathsplatform: "sessionize"platform: "luma" | "eventbrite"platform: "custom", strategy: "markdown" (best-effort fallback)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:
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.
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:
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).
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.
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):
After all subagents return, verify every company in seed_companies.txt has a corresponding companies/{slug}.md:
Clean up the batch files: rm {OUTPUT_DIR}/_batch_triage_*.
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:
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.
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)Agent dispatch (skeleton, repeat per batch in one message):
After all subagents return, verify the deep-research files exist and have triage_only: false:
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:
browse cloud search "{name} {company} linkedin" (always)browse cloud search "{name} podcast OR talk OR blog 2026" (deep+)browse cloud search "{name} github" (deeper)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.
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.
Then ask via AskUserQuestion — clean two-option choice with the quantified cost on each:
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.
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):
After all subagents return, verify the people files exist:
Generate the company-grouped HTML index, alternate views, and CSV in one command:
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 spreadsheetThen present a summary in chat:
Show the top 5 people cards as a markdown table sorted by company ICP score, then offer to:
--icp-threshold and re-run Steps 6-9