event-prospecting
browserbase/skills
Le service prend l'URL d'une conférence ou d'un événement, en extrait les intervenants, filtre leurs entreprises en fonction du profil de client cible (ICP) de l'utilisateur, puis effectue une recherche approfondie uniquement sur les intervenants issus d'entreprises correspondant à cet ICP. Il génère ensuite un rapport HTML centré sur les personnes, avec une justification « pourquoi les contacter » pour chacune d'entre elles.
...Développer toutProspection lors d'événements
À partir de l'URL d'une conférence → obtenez une liste classée des personnes avec lesquelles le commercial devrait prendre contact, accompagnée d'une justification « pourquoi les contacter » pour chacune d'entre elles.
Prérequis: la variable d’environnement BROWSERBASE_API_KEY et l’installation de la CLI browse (npm install -g browse). Utilisez browse cloud… pour les appels API et browse open / browse get markdown pour les pages de conférenciers riches en code JS.
Règles relatives aux chemins d’accès: utilisez toujours le chemin d’accès littéral complet dans toutes les commandes Bash — PAS ~ ni $HOME (ces deux éléments déclenchent des invites de validation de la « syntaxe d’expansion du shell »). Déterminez le répertoire de base une seule fois et utilisez-le partout. Lors de la création d’invites pour les sous-agents, remplacez {SKILL_DIR} par le chemin littéral complet (généralement /Users/jay/skills/skills/event-prospecting).
Répertoire de sortie: toutes les données issues de la prospection d’événements sont enregistrées dans ~/Desktop/{event_slug}_prospects_{AAAA-MM-JJ-HHMM}/. Le livrable final est le fichier index.html (personnes regroupées par entreprise, classées selon l’ICP de l’entreprise), avec les fichiers companies.html et people.html (filtrables) comme vues alternatives, ainsi que le fichier results.csv pour l’importation de prospects à froid.
IMPORTANT — Restrictions relatives à l’outil (s’appliquent à l’agent principal ET à tous les sous-agents):
- Toutes les recherches sur le Web : utilisez
la recherche « Browse Cloud». N’utilisez JAMAIS WebSearch. - Toute extraction de contenu de page : utilisez
le nœud {SKILL_DIR}/scripts/extract_page.mjs ". Ce script effectue la récupération via" `browse cloud fetch --output`, analyse le titre, les balises meta et le corps du texte visible, et bascule automatiquement vers `browse get markdown` lorsque la récupération échoue ou renvoie un contenu allégé rendu par JavaScript. Ne créez JAMAIS manuellement un pipeline `browse cloud fetch | sed`. N’utilisez JAMAIS WebFetch. - Tous les résultats de recherche : les sous-agents rédigent un fichier Markdown par entreprise OU par personne dans
{OUTPUT_DIR}/companies/{slug}.mdou{OUTPUT_DIR}/people/{slug}.mdà l’aide de la syntaxe heredoc de bash. N’utilisez JAMAIS l’outil « Write » ni lacommande python3 -c. Consultezreferences/example-research.mdpour les deux formats de fichier. - Compilation du rapport : utilisez
la commande node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open. - Les sous-agents doivent utiliser UNIQUEMENT l’outil Bash. Aucun autre outil n’est autorisé.
- LIMITES STRICTES DE NOMBRE D’APPELS: triage ICP = 1 appel/entreprise ; recherche approfondie = 5 appels/entreprise ; enrichissement des données sur les personnes = 4 appels/personne. Consultez
le fichier references/workflow.mdpour plus de détails sur l’application de ces règles.
CRITIQUE — Règles anti-hallucination (s'appliquent à l'agent principal ET à tous les sous-agents):
- Ne déduisez JAMAIS
la description du produit,le secteur d’activitéoula raison d’êtred’une personne à partir des polices, du framework, du système de conception ou de la typographie d’un site. Ces éléments sont purement esthétiques et ne renseignent en rien sur ce que vend l’entreprise ou sur ce que fait la personne. - NE JAMAIS laisser le profil ICP de l’utilisateur s’immiscer dans la description d’une cible. Si vous ne savez pas ce que fait la cible, écrivez
« Inconnu »— ne la faites pas correspondre au profil ICP. La « description du produit »DOIT citer ou paraphraser une phrase spécifique issue de la sortiedu fichier « extract_page.mjs». Si aucun des éléments TITLE/META/OG/HEADINGS/BODY ne fournit de description de produit identifiable, écrivez« Inconnu » — contenu de la page d’accueil inaccessible— et limitezle score « icp_fit_score »à 3.Le « hook »d’une personne DOIT citer ou paraphraser un résultat spécifique issu d’une recherche dans un « browse cloud »(titre de podcast, titre de blog, dépôt GitHub, résumé d’intervention). S’il n’existe aucun signal public au cours des 6 derniers mois, utilisez le contexte de l’événement (le titre de son intervention lors de cet événement).
CRITIQUE — Réduire au minimum les demandes d’autorisation:
- Les sous-agents DOIVENT regrouper TOUTES les écritures de fichiers en un SEUL appel Bash à l’aide de heredocs enchaînés. Un appel Bash = une demande d’autorisation.
- Regroupez TOUTES les recherches et TOUTES les récupérations dans des appels Bash uniques à l’aide du chaînage
&&.
Présentation du pipeline
Suivez ces 10 étapes dans l’ordre. Ne sautez aucune étape et ne les réorganisez pas.
- Configuration — répertoire de sortie + table rase
- Chargement du profil — lire
profiles/{user_slug}.json - Reconnaissance — détection de la plateforme d’événements
- Extraction des personnes —
people.jsonl - Regrouper par entreprise —
seed_companies.txt - Triage ICP — notation rapide au niveau de l’entreprise (1 appel/entreprise)
- Filtrage — entreprises dont
le score icp_fit_score est supérieur ou égal à --icp-threshold - Recherche approfondie — cycle complet Planification → Recherche → Synthèse sur les correspondances ICP
- Enrichir la liste des intervenants — demander à l’utilisateur : uniquement les profils adaptés à l’ICP (par défaut) ou tous les intervenants
- Compiler le rapport — HTML + CSV, ouvrir dans le navigateur
L’utilisateur lance la compétence via une URL du type /event-prospecting . Analysez EVENT_URL à partir de ce message d’appel. Valeurs par défaut : DEPTH=deep, ICP_THRESHOLD=6. L’USER_SLUG (profil ICP) est déterminé automatiquement à l’étape 1 à partir des fichiers de profil existant localement — il n’y a pas de profil par défaut intégré. Ne demandez PAS à l’utilisateur de confirmer l’URL — il vous l’a déjà fournie.
Étape 0 : Configuration du répertoire de sortie
Déterminez le répertoire de sortie à partir de l’URL que l’utilisateur vous a fournie. Ne codez PAS en dur le nom d’un événement.
# EVENT_URL provient du message d’invocation (ce que l’utilisateur a saisi après `/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"
Utilisez le chemin d'accès complet littéral — jamais ~ ou $HOME. Transmettez {OUTPUT_DIR} en tant que chemin d'accès complet littéral à toutes les invites des sous-agents.
Étape 1 : Charger le profil utilisateur
Le profil définit l’ICP sur lequel se basent le triage ICP et la recherche approfondie. Chargez-le à partir de {SKILL_DIR}/profiles/{user_slug}.json (interchangeable entre toutes les compétences GTM — même structure que la recherche sur les entreprises). example.json est un modèle, pas un vrai profil — ne l’utilisez jamais.
NE CHERCHEZ PAS de profilsen dehors de {SKILL_DIR}/profiles/ — n’accédez jamais aux répertoires d’autres compétences. Si un profil est nécessaire ailleurs, l’utilisateur doit le copier explicitement.
Ordre de résolution:
- Si l’utilisateur a lancé la commande avec l’option
--user-company, utilisez ce slug. - Sinon, répertoriez
les fichiers profiles/*.jsonen excluantexample.json. S’il n’existe qu’un seul profil, utilisez-le (et indiquez à l’utilisateur de quel profil il s’agit). S’il en existe plusieurs, demandez à l’utilisateur (via un chat simple) lequel il souhaite utiliser. - S’il n’existe aucun profil, signaler clairement l’échec et inviter l’utilisateur à en créer un (en copiant
profiles/example.jsonversprofiles/et en le complétant, ou en exécutant la compétence « company-research » qui en crée un automatiquement)..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 "Aucun profil trouvé dans {SKILL_DIR}/profiles/. Copiez le fichier profiles/example.json dans le répertoire profiles/.json et complétez-le, ou exécutez la compétence « company-research » pour en créer un."
exit 1
elif [ "$COUNT" -eq 1 ]; then
USER_SLUG=$PROFILES
echo "Utilisation du seul profil disponible : ${USER_SLUG}"
else
echo "Plusieurs profils trouvés :"
echo "$PROFILES" | sed 's/^/ - /'
echo « Relancez la commande avec --user-company pour en choisir un. »
exit 1
fi
fi
test -f {SKILL_DIR}/profiles/${USER_SLUG}.json || {
echo "Profil introuvable : profiles/${USER_SLUG}.json"
exit 1
}
cat {SKILL_DIR}/profiles/${USER_SLUG}.json
Le profil contient les champs suivants : company, product, icp_description, existing_customers. Ceux-ci sont intégrés tels quels dans chaque invite des sous-agents en aval.
Étape 2 : Reconnaissance
Détecter la plateforme d’événements et la stratégie d’extraction. Une seule commande :
node {SKILL_DIR}/scripts/recon.mjs {EVENT_URL} {OUTPUT_DIR}
Écrit le fichier {OUTPUT_DIR}/recon.json contenant la plateforme, la stratégie et (pour Next.js) nextDataPaths. Consultez le fichier references/event-platforms.md pour le catalogue des plateformes et la priorité de détection.
Résultats attendus :
- Classe Stripe Sessions (Next.js) :
platform: "next-data", 1 à 3 chemins - Sessionize :
plateforme : « sessionize » - Lu.ma / Eventbrite :
platform: "luma" | "eventbrite" - Tout autre cas :
platform: "custom",strategy: "markdown"(solution de secours au mieux)
Étape 3 : extraction des personnes
node {SKILL_DIR}/scripts/extract_event.mjs {OUTPUT_DIR} --user-company {USER_SLUG}
Lit le fichier recon.json, transmet les données à l’extracteur spécifique à la plateforme, écrit le fichier people.jsonl (un intervenant par ligne) et le fichier seed_companies.txt (entreprises dédupliquées).
L'option --user-company exclut également de la liste des intervenants les employés de l'organisation hôte (un événement hébergé par Stripe exclut les employés de Stripe) et les employés de l'utilisateur lui-même — ceux-ci ne sont pas des prospects.
Vérifiez la validité de la sortie :
wc -l {OUTPUT_DIR}/people.jsonl {OUTPUT_DIR}/seed_companies.txt
head -3 {OUTPUT_DIR}/people.jsonl
Si le fichier people.jsonl est vide ou comporte moins de 10 lignes, cela signifie que le système de reconnaissance a sélectionné la mauvaise plateforme — consultez le fichier references/event-platforms.md et relancez l’opération avec une stratégie adaptée.
Étape 4 : Regrouper par entreprise
extract_event.mjs génère déjà le fichier seed_companies.txt (une entreprise par ligne, sans doublons, trié). Cette étape est purement informative — vérifiez que le nombre semble raisonnable avant de passer à l’étape suivante :
wc -l {OUTPUT_DIR}/seed_companies.txt
Résultat attendu : environ 0,4 à 0,6 fois le nombre d’intervenants (la plupart des événements comptent en moyenne environ 2 intervenants par entreprise ; certaines entreprises en envoient plus de 5, tandis que beaucoup n’en envoient qu’un).
Étape 5 : Triage ICP
Triage rapide — un appel d’outil par entreprise, sans recherche approfondie. Attribuez un score à chaque entreprise du fichier seed_companies.txt par rapport à l’ICP de l’utilisateur et rédigez une brève note de triage dans le fichier companies/{slug}.md. Les entreprises dont le score icp_fit_score est supérieur ou égal à --icp-threshold (valeur par défaut : 6) passent à l’étape 7 (recherche approfondie) ; les autres restent sous forme de brouillons de triage.
Modèle de répartition: diviser le fichier seed_companies.txt en lots d’environ 10 et répartir N sous-agents dans un SEUL lot d’Agent (plusieurs appels d’outils Agent dans un seul message). Chaque sous-agent exécute la prompt issue du fichier references/workflow.md → section « ICP Triage ». Limite stricte : 1 appel d’outil par entreprise (uniquement extract_page.mjs sur la page d’accueil), appliquée via le modèle de commentaire # browse call N/1.
# Création des fichiers de lots : chaque ligne de lot est au format « nom|page_d’accueil_devinee|slug ».
# extract_event.mjs ne renvoie que les NOMS d’entreprises (pas d’URL), nous générons donc un slug et devinons
# https://{slug-sans-espaces}.com comme page d’accueil canonique. Le sous-agent de triage
# est autorisé à écrire product_description : « Inconnu — contenu de la page d’accueil inaccessible »
# et à fixer le score à 3 si l’URL devinée renvoie une erreur 404 — c’est la solution de secours documentée dans
# workflow.md (règle n° 3 de l’invite de triage ICP). Lancer une véritable recherche dans le nuage de navigation pour
# découvrir l’URL ferait sauter la LIMITE STRICTE d’un appel par entreprise.
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");
'
# Répartition en lots d’environ 10 entreprises
split -l 10 {OUTPUT_DIR}/_seed_with_urls.txt {OUTPUT_DIR}/_batch_triage_
# Compter les lots → nombre de sous-agents à envoyer (plafonné à 6 par message ; deuxième vague pour le reste)
ls {OUTPUT_DIR}/_batch_triage_* | wc -l
Puis, dans un seul message, envoyer un appel d’agent par lot (jusqu’à 6 en parallèle ; vagues suivantes après le retour de la première). Chaque agent reçoit l’invite de references/workflow.md → « ICP Triage » avec ces substitutions avant l’envoi :
{SKILL_DIR}→ chemin littéral complet de la compétence (par ex./Users/jay/skills/skills/event-prospecting){OUTPUT_DIR}→ chemin littéral complet de la sortie{USER_COMPANY},{USER_PRODUCT},{ICP_DESCRIPTION}→ à partir du profil chargé{EVENT_NAME}→.titledu fichierrecon.json{COMPANY_LIST}→ contenu du fichier batch (par ex.cat {OUTPUT_DIR}/_batch_triage_aa){TOTAL}→ nombre de lignes dans ce lot (à substituer dansl’appel # browse N/{TOTAL})
Envoi de l'agent (squelette, à répéter pour chaque lot dans un seul message):
Agent(
description : « ICP triage lot aa »,
prompt : ,
subagent_type : « general-purpose »
)
Agent(
description : « Triage ICP lot ab »,
invite : ,
type_de_sous-agent : « usage général »
)
... jusqu'à 6 par message
Une fois que tous les sous-agents ont renvoyé leur résultat, vérifiez que chaque entreprise de seed_companies.txt dispose d’un fichier correspondant companies/{slug}.md:
ls {OUTPUT_DIR}/companies/*.md | wc -l
# Doit être égal à `wc -l {OUTPUT_DIR}/seed_companies.txt`
Nettoyez les fichiers batch : rm {OUTPUT_DIR}/_batch_triage_*.
Étape 6 : Filtrer selon le seuil ICP
Lire les métadonnées de chaque fichier companies/*.md, ne conserver que ceux dont icp_fit_score est >= 6 (ou quelle que soit la valeur de --icp-threshold ). Écrire les slugs des entreprises retenues dans {OUTPUT_DIR}/icp_fits.txt:
THRESHOLD=6 # issu de l’option --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
Résultat attendu : 20 à 40 % du fichier seed_companies.txt. Si le taux de survie est inférieur à 10 %, le seuil est peut-être trop élevé ou la description de l’ICP trop restrictive — afficher un avertissement à l’utilisateur.
Étape 7 : Recherche approfondie
Plan complet → Recherche → Synthèse portant uniquement sur les entreprises correspondant à l’ICP. Limite stricte : 5 appels d’outils par entreprise (extrait de la page d’accueil + 2 à 3 recherches par sous-question + 1 à 2 récupérations supplémentaires). Les sous-agents REMPLACENT l’ébauche de triage existante companies/{slug}.md par la version enrichie issue de la recherche approfondie (frontmatter triage_only : false).
Modèle de distribution: diviser le fichier icp_fits.txt en lots d’environ 5 (mode approfondi par défaut) et répartir un agent par lot dans un SEUL message (jusqu’à 6 agents par message). Chaque agent reçoit la consigne issue du fichier references/workflow.md → « Recherche approfondie » avec les substitutions suivantes :
{SKILL_DIR},{OUTPUT_DIR},{USER_COMPANY},{USER_PRODUCT},{ICP_DESCRIPTION}{EVENT_NAME}(à partir de.titledans recon.json),{EVENT_CONTEXT}(thème / sujet, déduit manuellement à partir de la page d’accueil de l’événement){COMPANY_LIST}→ contenu du fichier batch (chaque ligneslug|site web)
# Créer des paires {slug-entreprise|site-web} en lisant les métadonnées de chaque ébauche de triage
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
# Division en lots d’environ 5 entreprises (mode approfondi)
split -l 5 {OUTPUT_DIR}/_deep_targets.txt {OUTPUT_DIR}/_batch_deep_
ls {OUTPUT_DIR}/_batch_deep_* | wc -l
Déploiement des agents (squelette, à répéter pour chaque lot dans un seul message):
Agent(
description : "Lot de recherche approfondie aa",
prompt : ,
subagent_type : "usage général"
)
Agent(
description : "Lot de recherche approfondie ab",
invite : ,
type_de_sous-agent : "usage général"
)
... jusqu’à 6 par message ; deuxième vague après le retour de la première
Une fois que tous les sous-agents ont renvoyé leur résultat, vérifiez que les fichiers de recherche approfondie existent et que la valeur triage_only: false est présente :
grep -l "triage_only: false" {OUTPUT_DIR}/companies/*.md | wc -l
# Doit donner le même résultat que wc -l icp_fits.txt
Étape 8 : Enrichir les intervenants
Par personne : récupérer l’URL LinkedIn, l’activité récente (podcast / blog / conférence / GitHub / X), et créer le fichier people/{slug}.md. Limite stricte : 4 appels d’outils par personne, trois voies :
recherche dans le cloud « {nom} {entreprise} linkedin »(toujours)recherche dans le cloud « {nom} podcast OU conférence OU blog 2026 »(approfondie+)recherche dans le cloud « {nom} github »(plus approfondie)recherche dans le nuage « {nom} site:x.com OU site:twitter.com »(plus approfondie, au mieux)
Mode rapide : ignorer complètement l’étape 8. Mode approfondi : voies 1 et 2. Mode plus approfondi : voies 1 à 4.
Étape 8a — Demander à l’utilisateur : portée de l’enrichissement
Avant l’envoi, calculez le nombre de candidats pour chaque option et demandez à l’utilisateur de choisir. Par défaut, seule l’adaptation ICP est utilisée (plus rapide, moins coûteuse, ce que la plupart des utilisateurs souhaitent) ; l’enrichissement de chaque intervenant est facultatif, car le coût augmente linéairement avec le nombre de personnes enrichies.
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);
')
# Nombre de voies par personne : 2 (profond) ou 4 (plus profond) — correspond à {DEPTH}
LANES=2 # ou 4 pour plus de profondeur
echo "Correspondances ICP : ${ICP_FITS} intervenants × ${LANES} = $((ICP_FITS * LANES)) appels"
echo "Total : ${TOTAL} intervenants × ${LANES} = $((TOTAL * LANES)) appels"
Puis poser la question via AskUserQuestion — choix clair à deux options avec le coût quantifié pour chacune :
AskUserQuestion(questions: [
{
question: "Quels locuteurs enrichir ?",
header: "Portée de l’enrichissement",
multiSelect: false,
options: [
{ label: "ICP FITS uniquement", description: "${ICP_FITS} haut-parleurs, environ $((ICP_FITS * LANES)) appels (recommandé)" },
{ label: "Tous les locuteurs", description: "${TOTAL} locuteurs, environ $((TOTAL * LANES)) appels" }
]
}
])
Enregistrez la portée choisie sous ENRICH_SCOPE=icp_fits ou ENRICH_SCOPE=all. Si l’utilisateur choisit « Tous les locuteurs » et que TOTAL × LANES > 600, affichez un avertissement et demandez-lui de confirmer — cela correspond à une exécution de plus de 10 minutes avec des centaines d’appels à l’outil.
Étape 8b — Filtrage et traitement par lots
# Créer le fichier _people_to_enrich.jsonl en fonction de 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(`Enrichissement de ${keep.length} intervenants sur ${lines.length}`);
'
fi
# Répartition en lots d’environ 5 personnes
split -l 5 {OUTPUT_DIR}/_people_to_enrich.jsonl {OUTPUT_DIR}/_batch_people_
Ensuite, dans un seul message, envoyez un appel d’agent par lot (jusqu’à 6 par message) avec l’invite tirée de references/workflow.md → « Person Enrichment ». L’invite de chaque sous-agent doit inclure :
{SKILL_DIR},{OUTPUT_DIR},{DEPTH}(deep|deeper){USER_COMPANY},{USER_PRODUCT},{ICP_DESCRIPTION}{EVENT_NAME}(à partir derecon.json.title){LANES}→2pour le mode « deep »,4pour le mode « deeper » (à insérer dansl’appel # browse N/{LANES}){PEOPLE_BATCH}→ contenu de_batch_people_aa(chaque ligne correspondant à un enregistrement JSON issu depeople.jsonl)
Envoi d’agents (squelette, à répéter pour chaque lot dans un seul message):
Agent(
description : « Lot d’enrichissement des données personnelles aa »,
prompt : ,
subagent_type : « usage général »
)
Agent(
description : « Lot d’enrichissement des données sur les personnes ab »,
prompt : ,
subagent_type : « general-purpose »
)
... jusqu’à 6 par message
Une fois que tous les sous-agents ont renvoyé leur résultat, vérifiez que les fichiers relatifs aux personnes existent :
ls {OUTPUT_DIR}/people/*.md | wc -l
# Doit être égal à wc -l _people_to_enrich.jsonl
Étape 9 : Compiler le rapport
Générez l’index HTML regroupé par entreprise, les vues alternatives et le fichier CSV en une seule commande :
node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open
Cela génère :
{OUTPUT_DIR}/index.html— personnes regroupées par entreprise, classées selon le score ICP de l’entreprise (s’ouvre dans le navigateur){OUTPUT_DIR}/people.html— liste des intervenants filtrable (vue alternative){OUTPUT_DIR}/companies.html— tableau des entreprises classées selon l’ICP, avec les participants{OUTPUT_DIR}/results.csv— feuille de calcul prête à l’emploi pour la prospection à froid
Présentez ensuite un résumé dans le chat :
## Prospection de l’événement terminée — {Nom de l’événement}
- **Nombre total d’intervenants extraits** : {nombre}
- **Entreprises uniques** : {nombre}
- **Adéquation ICP (score ≥ {seuil})** : {nombre}
- **Intervenants enrichis** : {nombre}
- **Répartition des scores** (entreprises) :
- Adéquation forte (8-10) : {nombre}
- Adéquation partielle (5-7) : {nombre}
- Adéquation faible (1-4) : {nombre}
- **Rapport ouvert dans le navigateur** : {OUTPUT_DIR}/index.html
Afficher les 5 premières fiches de personnes sous forme de tableau Markdown trié par score ICP de l’entreprise, puis proposer de :
- Ajuster
--icp-thresholdet relancer les étapes 6 à 9 - Exporter le fichier CSV vers un 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
Tous les fichiers
14 fichiersInstaller event-prospecting
Téléchargez et décompressez les fichiers de compétences dans votre répertoire .claude/skills/.
Télécharger le ZIPClonez le dépôt et copiez les fichiers de compétence dans votre projet.
git clone https://github.com/browserbase/skills/tree/main/skills/event-prospecting # Copy SKILL.md to your .claude/skills/ directory
Copier





Maison
