Option
HeimHeim Skill Sonstiges event-prospecting

event-prospecting

browserbase/skills browserbase/skills

Nimmt die URL einer Konferenz oder Veranstaltung mit Referenten, extrahiert die Personen, filtert deren Unternehmen anhand des ICP des Nutzers und recherchiert nur die Referenten bei Unternehmen, die zum ICP passen. Erzeugt einen personenbezogenen HTML-Bericht mit einer Begründung „Warum Kontakt aufnehmen?“ für jede Person.

...Alle erweitern
0
Zeit aktualisiert 30. September 2026

Akquise auf Veranstaltungen

Geben Sie eine Konferenz-URL ein → erhalten Sie eine nach Relevanz sortierte Liste der Personen, mit denen der AE sprechen sollte, mit einer Begründung pro Person, warum Kontakt aufgenommen werden sollte.

Voraussetzungen: Die Umgebungsvariable BROWSERBASE_API_KEY und die installierte browse-CLI (npm install -g browse). Verwenden Sie „browse cloud ...“ für API-Aufrufe und „browse open “ bzw. „browse get markdown“ für JS-lastige Referentenseiten.

Pfadregeln: Verwenden Sie in allen Bash-Befehlen immer den vollständigen literalen Pfad – NICHT ~ oder $HOME (beides löst Bestätigungsaufforderungen für die „Shell-Erweiterungssyntax“ aus). Lösen Sie das Home-Verzeichnis einmalig auf und verwenden Sie es überall. Ersetzen Sie beim Erstellen von Subagent-Eingabeaufforderungen {SKILL_DIR} durch den vollständigen literalen Pfad (typischerweise /Users/jay/skills/skills/event-prospecting).

Ausgabeverzeichnis: Alle Ergebnisse der Event-Prospektion werden unter ~/Desktop/{event_slug}_prospects_{YYYY-MM-DD-HHMM}/ gespeichert. Das Endergebnis ist die Datei „index.html“ (Personen gruppiert nach Unternehmen, sortiert nach dem ICP des Unternehmens), mit „companies.html“ und „people.html“ (filterbar) als alternative Ansichten sowie „results.csv“ für den Import in die Kaltakquise.

WICHTIG – Tool-Einschränkungen (gilt für den Hauptagenten UND alle Unteragenten):

  • Alle Websuchen: Verwenden Sie die Cloud-Suche. Verwenden Sie NIEMALS WebSearch.
  • Alle Extraktionen von Seiteninhalten: Verwenden Sie den Knoten {SKILL_DIR}/scripts/extract_page.mjs „ “. Dieses Skript ruft Daten über „browse cloud fetch --output“ ab, analysiert Titel, Meta-Tags und sichtbaren Text im Hauptteil und greift automatisch auf „browse get markdown“ zurück, wenn der Abruf fehlschlägt oder nur spärliche, per JavaScript gerenderte Inhalte zurückgibt. Erstellen Sie NIEMALS eine eigene „browse cloud fetch | sed“-Pipeline. Verwenden Sie NIEMALS WebFetch.
  • Alle Forschungsergebnisse: Unteragenten schreiben eine Markdown-Datei pro Unternehmen ODER pro Person in {OUTPUT_DIR}/companies/{slug}.md oder {OUTPUT_DIR}/people/{slug}.md unter Verwendung von Bash-Heredoc. Verwende NIEMALS das „Write“-Tool oder „python3 -c“. Beide Dateiformate findest du in „references/example-research.md “.
  • Zusammenstellung des Berichts: Verwenden Sie den Befehl ` node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --open`.
  • Unterbeauftragte dürfen AUSSCHLIESSLICH das Bash-Tool verwenden. Andere Tools sind nicht zulässig.
  • STRENGE GRENZEN FÜR TOOL-AUFRUFE: ICP-Triage = 1 Aufruf/Unternehmen; eingehende Recherche = 5 Aufrufe/Unternehmen; Personenanreicherung = 4 Aufrufe/Person. Details zur Durchsetzung finden Sie in references/workflow.md.

KRITISCH – Regeln gegen „Halluzinationen“ (gilt für den Hauptagenten UND alle Unteragenten):

  • Leiten Sie NIEMALS die Produktbeschreibung, die Branche oder den Aufgabenbereich einer Person aus den Schriftarten, dem Framework, dem Designsystem oder der Typografie einer Website ab. Diese Aspekte sind rein kosmetischer Natur und sagen nichts darüber aus, was das Unternehmen verkauft oder was die Person tut.
  • Lassen Sie NIEMALS das eigene ICP des Nutzers in die Beschreibung eines Ziels einfließen. Wenn Sie nicht wissen, was das Ziel tut, schreiben Sie „Unbekannt“ – ordnen Sie es nicht anhand von Mustern dem ICP zu.
  • „product_description“ MUSS einen bestimmten Ausdruck aus der Ausgabe von „extract_page.mjs“ wörtlich zitieren oder umschreiben. Wenn weder TITLE noch META noch OG noch HEADINGS noch BODY eine erkennbare Produktbeschreibung liefern, schreiben Sie „Unbekannt“ – Inhalt der Startseite nicht zugänglich – und begrenzen Sie den „icp_fit_score“ auf 3.
  • Der „Hook“ einer Person MUSS eine bestimmte Information aus einem Suchergebnis der Browse-Cloud zitieren oder umschreiben (Podcast-Titel, Blog-Überschrift, GitHub-Repo, Abstract eines Vortrags). Falls in den letzten 6 Monaten kein öffentliches Signal vorliegt, greife auf den Veranstaltungskontext zurück (den Titel ihres Vortrags bei dieser Veranstaltung).

KRITISCH – Berechtigungsabfragen minimieren:

  • Unteragenten MÜSSEN ALLE Dateischreibvorgänge mithilfe verketteter Heredocs in einem EINZIGEN Bash-Aufruf bündeln. Ein Bash-Aufruf = eine Berechtigungsabfrage.
  • Fassen Sie ALLE Suchvorgänge und ALLE Abrufe mithilfe von && -Verkettung in einzelne Bash-Aufrufe zusammen.

Pipeline-Übersicht

Befolgen Sie diese 10 Schritte der Reihe nach. Überspringen Sie keine Schritte und ändern Sie die Reihenfolge nicht.

  1. Einrichtung – Ausgabeverzeichnis + Neuanfang
  2. Profil laden – „profiles/{user_slug}.json“ einlesen
  3. Erkundung – Ereignisplattform erkennen
  4. Personen extrahieren – people.jsonl
  5. Nach Unternehmen gruppieren – seed_companies.txt
  6. ICP-Triage – schnelle Bewertung auf Unternehmensebene (1 Aufruf/Unternehmen)
  7. Filter – Unternehmen mit icp_fit_score >= --icp-threshold
  8. Eingehende Recherche — vollständiger Prozess „Planen → Recherchieren → Zusammenfassen“ zu ICP-Übereinstimmungen
  9. Referenten ergänzen – Benutzer abfragen: nur ICP-Passung (Standard) oder alle Referenten
  10. Bericht erstellen – HTML + CSV, im Browser öffnen

Der Nutzer ruft die Funktion mit einer URL wie /event-prospecting auf. Analysiere EVENT_URL aus dieser Aufrufnachricht. Standardwerte: DEPTH=deep, ICP_THRESHOLD=6. Der USER_SLUG (ICP-Profil) wird in Schritt 1 automatisch aus den lokal vorhandenen Profildateien ermittelt – es gibt kein integriertes Standardprofil. Bitten Sie den Benutzer NICHT um Bestätigung der URL – er hat sie Ihnen bereits mitgeteilt.

Schritt 0: Ausgabeverzeichnis einrichten

Leiten Sie das Ausgabeverzeichnis aus der URL ab, die der Benutzer Ihnen angegeben hat. Fügen Sie KEINEN Ereignisnamen fest ein.

# EVENT_URL stammt aus der Aufrufmeldung (alles, was der Benutzer nach `/event-prospecting` eingegeben hat)
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"

Verwenden Sie den vollständigen absoluten Pfad – niemals ~ oder $HOME. Übergeben Sie {OUTPUT_DIR} als vollständigen absoluten Pfad an alle Subagent-Eingabeaufforderungen.

Schritt 1: Benutzerprofil laden

Das Profil definiert das ICP, anhand dessen die ICP-Triage und die Deep-Research-Bewertung erfolgen. Laden Sie es aus {SKILL_DIR}/profiles/{user_slug}.json (austauschbar zwischen allen GTM-Skills – gleiche Struktur wie bei der Unternehmensrecherche). example.json ist eine Vorlage, kein echtes Profil – verwenden Sie es niemals.

Suchen Sie NICHT außerhalb von {SKILL_DIR}/profiles/ nach Profilen – greifen Sie niemals auf die Verzeichnisse anderer Skills zu. Wenn ein Profil an anderer Stelle benötigt wird, kopiert der Benutzer es explizit.

Auflösungsreihenfolge:

  1. Wenn der Benutzer den Befehl mit --user-company aufgerufen hat, verwende diesen Slug.
  2. Andernfalls liste „profiles/*.json“ unter Ausschluss von „example.json“ auf. Wenn genau ein Profil vorhanden ist, verwende es (und teile dem Benutzer mit, welches). Wenn mehrere vorhanden sind, frage den Benutzer (im einfachen Chat), welches er möchte.
  3. Wenn kein Profil vorhanden ist, melde einen deutlichen Fehler und weise den Nutzer an, eines zu erstellen (kopiere „profiles/example.json“ nach „profiles/.json“ und fülle es aus oder führe das Skill „company-research“ aus, das automatisch eines erstellt).
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 „In {SKILL_DIR}/profiles/ wurden keine Profile gefunden. Kopiere die Datei profiles/example.json nach profiles/.json und fülle sie aus, oder führe den Skill „company-research“ aus, um ein Profil zu erstellen.“
    exit 1
  elif [ „$COUNT“ -eq 1 ]; then
    USER_SLUG=$PROFILES
    echo „Das einzige verfügbare Profil wird verwendet: ${USER_SLUG}“
  else
    echo „Mehrere Profile gefunden:“
    echo „$PROFILES“ | sed 's/^/  - /'
    echo „Führe den Befehl erneut mit --user-company  aus, um eines auszuwählen.“
    exit 1
  fi
fi

test -f {SKILL_DIR}/profiles/${USER_SLUG}.json || {
  echo "Profil nicht gefunden: profiles/${USER_SLUG}.json"
  exit 1
}
cat {SKILL_DIR}/profiles/${USER_SLUG}.json

Das Profil enthält: company, product, icp_description, existing_customers. Diese werden unverändert in jede nachfolgende Subagent-Eingabeaufforderung eingebettet.

Schritt 2: Erkundung

Ermitteln Sie die Ereignisplattform und die Extraktionsstrategie. Ein Befehl:

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

Schreibt die Datei {OUTPUT_DIR}/recon.json mit Plattform, Strategie und (für Next.js) nextDataPaths. Siehe references/event-platforms.md für den Plattformkatalog und die Erkennungspriorität.

Erwartete Ergebnisse:

  • Stripe Sessions-Klasse (Next.js): platform: „next-data“, 1–3 Pfade
  • Sessionize: platform: „sessionize“
  • Lu.ma / Eventbrite: platform: „luma“ | „eventbrite“
  • Sonstiges: platform: „custom“, strategy: „markdown“ (Best-Effort-Fallback)

Schritt 3: Personen extrahieren

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

Liest „recon.json“, leitet die Daten an den plattformspezifischen Extraktor weiter und schreibt „people.jsonl“ (ein Redner pro Zeile) sowie „seed_companies.txt“ (deduplizierte Unternehmen).

Das Flag „--user-company“ entfernt außerdem die Mitarbeiter der veranstaltenden Organisation (bei einer von Stripe veranstalteten Veranstaltung werden Stripe-Mitarbeiter entfernt) sowie die eigenen Mitarbeiter des Nutzers aus der Rednerliste – diese gelten nicht als potenzielle Kunden.

Überprüfen Sie die Ausgabe:

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

Wenn „people.jsonl“ leer ist oder weniger als 10 Zeilen enthält, hat „recon“ die falsche Plattform ausgewählt – siehe „references/event-platforms.md“ und führen Sie den Vorgang mit einer angepassten Strategie erneut aus.

Schritt 4: Nach Unternehmen gruppieren

„extract_event.mjs“ gibt bereits die Datei „seed_companies.txt“ aus (ein Unternehmen pro Zeile, dedupliziert, sortiert). Dieser Schritt dient der Information – überprüfe, ob die Anzahl plausibel erscheint, bevor du weitermachst:

wc -l {OUTPUT_DIR}/seed_companies.txt

Erwartet: etwa das 0,4- bis 0,6-Fache der Referentenanzahl (die meisten Veranstaltungen haben im Durchschnitt ~2 Referenten pro Unternehmen, einige Unternehmen entsenden 5 oder mehr, viele nur 1).

Schritt 5: ICP-Triage

Schnelldurchlauf – ein Tool-Aufruf pro Unternehmen, keine eingehende Recherche. Bewerten Sie jedes Unternehmen in „seed_companies.txt“ anhand des ICP des Nutzers und schreiben Sie einen kurzen Triage-Stub in „companies/{slug}.md“. Unternehmen mit einem icp_fit_score >= --icp-threshold (Standardwert 6) gelangen zur eingehenden Recherche in Schritt 7; die übrigen bleiben als Triage-Stubs erhalten.

Verteilungsmuster: Aufteilung von „seed_companies.txt“ in Batches von ~10 und Verteilung von N Unteragenten in einem EINZIGEN Agent-Batch (mehrere Agent-Tool-Aufrufe in einer Nachricht). Jeder Unteragent führt die Eingabeaufforderung aus „references/workflow.md“ → Abschnitt „ICP-Triage“ aus. Harte Obergrenze: 1 Tool-Aufruf pro Unternehmen (nur ` extract_page.mjs ` auf der Startseite), durchgesetzt über das Kommentar-Muster # browse call N/1.

# Batch-Dateien erstellen: Jede Zeile im Batch lautet „name|guessed_homepage|slug“.
# extract_event.mjs gibt nur Firmennamen (keine URLs) aus, daher erstellen wir Slugs und schätzen
# https://{slug-without-spaces}.com als kanonische Startseite. Der Triage-Subagent
# darf „product_description: ‚Unbekannt – Inhalt der Startseite nicht zugänglich‘“ schreiben
# und den Score auf 3 begrenzen, wenn die erratene URL einen 404-Fehler liefert – das ist der dokumentierte Fallback in
# workflow.md (Regel 3 der ICP-Triage-Anweisung). Eine echte Suche in der Browse-Cloud durchzuführen, um
# die URL zu ermitteln, würde die HARDE OBERGRENZE von einem Aufruf pro Unternehmen überschreiten.
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");
'

# In Batches mit jeweils ca. 10 Unternehmen aufteilen
split -l 10 {OUTPUT_DIR}/_seed_with_urls.txt {OUTPUT_DIR}/_batch_triage_

# Anzahl der Stapel → Anzahl der zu entsendenden Subagenten (maximal 6 pro Nachricht; zweite Welle für den Rest)
ls {OUTPUT_DIR}/_batch_triage_* | wc -l

Anschließend in einer einzigen Nachricht einen Agent-Aufruf pro Stapel versenden (bis zu 6 parallel; weitere Wellen, nachdem die erste zurückgekehrt ist). Jeder Agent erhält vor dem Versenden die Eingabeaufforderung aus references/workflow.md → „ICP Triage“ mit folgenden Ersetzungen:

  • {SKILL_DIR} → vollständiger, wörtlicher Skill-Pfad (z. B. /Users/jay/skills/skills/event-prospecting)
  • {OUTPUT_DIR} → vollständiger literaler Ausgabepfad
  • {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION} → aus dem geladenen Profil
  • {EVENT_NAME} → „recon.json .title“
  • {COMPANY_LIST} → Inhalt der Batch-Datei (z. B. cat {OUTPUT_DIR}/_batch_triage_aa)
  • {TOTAL} → Anzahl der Zeilen in diesem Batch (in den #-Browse-Aufruf N/{TOTAL} einfügen)

Agentenversand (Grundgerüst, pro Batch in einer Nachricht wiederholen):

Agent(
  description: „ICP-Triage-Batch aa“,
  prompt: ,
  subagent_type: „general-purpose“
)
Agent(
  description: "ICP-Triage-Stapel ab",
  prompt: ,
  subagent_type: "general-purpose"
)
... bis zu 6 pro Nachricht

Nachdem alle Unteragenten zurückgekehrt sind, überprüfe, ob für jedes Unternehmen in „seed_companies.txt“ eine entsprechende Datei „companies/{slug}.md“ vorhanden ist:

ls {OUTPUT_DIR}/companies/*.md | wc -l
# Sollte gleich `wc -l {OUTPUT_DIR}/seed_companies.txt` sein

Batch-Dateien bereinigen: rm {OUTPUT_DIR}/_batch_triage_*.

Schritt 6: Nach ICP-Schwellenwert filtern

Lies den Frontmatter jeder Datei „companies/*.md“ und behalte diejenigen mit einem „icp_fit_score“ >= 6 (oder dem Wert, der für „--icp-threshold“ festgelegt wurde). Schreibe die Slugs der verbleibenden Unternehmen in „{OUTPUT_DIR}/icp_fits.txt“:

THRESHOLD=6   # aus dem Flag --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

Erwartet: 20–40 % von „seed_companies.txt“. Liegt die Überlebensrate unter 10 %, ist der Schwellenwert möglicherweise zu hoch oder die ICP-Beschreibung zu eng gefasst – gib dem Benutzer eine Warnung aus.

Schritt 7: Eingehende Recherche

Vollständiger Plan → Recherche → Zusammenfassung ausschließlich für ICP-konforme Unternehmen. Strenge Obergrenze: 5 Tool-Aufrufe pro Unternehmen (Auszug aus der Homepage + 2–3 Suchanfragen zu Teilfragen + 1–2 ergänzende Abrufe). Unteragenten ÜBERSCHREIBEN den bestehenden Triage-Stub „companies/{slug}.md“ mit der ausführlicheren Version aus der eingehenden Recherche (Frontmatter „triage_only“: false).

Verteilungsmuster: icp_fits.txt in Stapel von ca. 5 aufteilen (Standard im Deep-Modus) und pro Stapel einen Agenten in einer EINZIGEN Nachricht verteilen (bis zu 6 Agenten pro Nachricht). Jeder Agent erhält die Eingabeaufforderung aus references/workflow.md → „Deep Research“ mit folgenden Ersetzungen:

  • {SKILL_DIR}, {OUTPUT_DIR}, {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION}
  • {EVENT_NAME} (aus „recon.json .title“), {EVENT_CONTEXT} (Track/Thema, manuell aus der Veranstaltungshomepage abgeleitet)
  • {COMPANY_LIST} → Inhalt der Batch-Datei (jede Zeile: Slug|Website)
# Erstellen von {company-slug|website}-Paaren durch Auslesen des Frontmatter aus jedem 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

# In Batches mit ca. 5 Unternehmen aufteilen (Deep-Modus)
split -l 5 {OUTPUT_DIR}/_deep_targets.txt {OUTPUT_DIR}/_batch_deep_
ls {OUTPUT_DIR}/_batch_deep_* | wc -l

Agentenverteilung (Grundgerüst, pro Batch in einer Nachricht wiederholen):

Agent(
  description: „Deep-Research-Batch aa“,
  prompt: ,
  subagent_type: „general-purpose“
)
Agent(
  description: "Deep-Research-Batch ab",
  prompt: ,
  subagent_type: "general-purpose"
)
... bis zu 6 pro Nachricht; zweite Welle, nachdem die erste zurückgekehrt ist

Nachdem alle Unteragenten zurückgekehrt sind, überprüfe, ob die Deep-Research-Dateien vorhanden sind und „triage_only: false“ enthalten:

grep -l "triage_only: false" {OUTPUT_DIR}/companies/*.md | wc -l
# Sollte gleich wc -l icp_fits.txt sein

Schritt 8: Referenten anreichern

Pro Person: LinkedIn-URL und aktuelle Aktivitäten (Podcast / Blog / Vortrag / GitHub / X) erfassen und die Datei people/{slug}.md erstellen. Obergrenze: 4 Tool-Aufrufe pro Person, drei Wege:

  1. Browse-Cloud-Suche „{Name} {Unternehmen} linkedin“ (immer)
  2. Browse-Cloud-Suche „{Name} Podcast ODER Vortrag ODER Blog 2026“ (tief+)
  3. Browse-Cloud-Suche „{Name} GitHub“ (tiefer)
  4. Browse-Cloud-Suche „{Name} site:x.com ODER site:twitter.com“ (tiefer, nach bestem Bemühen)

Schnellmodus: Schritt 8 komplett überspringen. Tiefenmodus: Spuren 1–2. Tieferer Modus: Spuren 1–4.

Schritt 8a – Den Nutzer fragen: Umfang der Anreicherung

Berechnen Sie vor der Weiterleitung die Anzahl der beiden Kandidaten und bitten Sie den Benutzer, eine Auswahl zu treffen. Die Standardeinstellung ist ausschließlich ICP-Fit (schneller, kostengünstiger, was die meisten Benutzer wünschen); die Anreicherung aller Sprecher ist optional, da die Kosten linear mit der Anzahl der angereicherten Personen steigen.

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);
')

# Spuren pro Person: 2 (tief) oder 4 (tiefer) – passt zu {DEPTH}
LANES=2   # oder 4 für tiefer
echo "ICP-Übereinstimmungen: ${ICP_FITS} Sprecher × ${LANES} = $((ICP_FITS * LANES)) Aufrufe"
echo "Insgesamt:      ${TOTAL} Sprecher × ${LANES} = $((TOTAL * LANES)) Anrufe"

Anschließend über „AskUserQuestion“ abfragen – übersichtliche Auswahl mit zwei Optionen und den jeweiligen quantifizierten Kosten:

AskUserQuestion(questions: [
  {
    question: "Welche Sprecher sollen angereichert werden?",
    header: "Anreicherungsumfang",
    multiSelect: false,
    options: [
      { label: "Nur ICP-Fits", description: "${ICP_FITS} Sprecher, ~$((ICP_FITS * LANES)) Anrufe (empfohlen)" },
      { label: „Alle Sprecher“, description: „${TOTAL} Sprecher, ~$((TOTAL * LANES)) Anrufe“ }
    ]
  }
])

Speichern Sie den gewählten Umfang als ENRICH_SCOPE=icp_fits oder ENRICH_SCOPE=all. Wenn der Benutzer „Alle Sprecher“ auswählt und TOTAL × LANES > 600 ist, geben Sie eine Warnung aus und fragen Sie noch einmal nach – das ist ein Lauf von mehr als 10 Minuten mit Hunderten von Tool-Aufrufen.

Schritt 8b – Filtern und stapelweise verarbeiten

# Erstelle _people_to_enrich.jsonl basierend auf 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(`Anreicherung von ${keep.length} von ${lines.length} Referenten`);
'
fi

# In Stapel zu je ~5 Personen aufteilen
split -l 5 {OUTPUT_DIR}/_people_to_enrich.jsonl {OUTPUT_DIR}/_batch_people_

Anschließend in einer einzigen Nachricht einen Agenten-Aufruf pro Stapel (bis zu 6 pro Nachricht) mit der Aufforderung aus references/workflow.md → „Person Enrichment“ versenden. Die Aufforderung jedes Unteragenten sollte Folgendes enthalten:

  • {SKILL_DIR}, {OUTPUT_DIR}, {DEPTH} (deep | deeper)
  • {USER_COMPANY}, {USER_PRODUCT}, {ICP_DESCRIPTION}
  • {EVENT_NAME} (aus recon.json .title)
  • {LANES} → 2 für den „deep“-Modus, 4 für den „deeper“-Modus (wird in den #-Browse-Aufruf N/{LANES} eingesetzt)
  • {PEOPLE_BATCH} → Inhalt von _batch_people_aa (jede Zeile ein JSON-Datensatz aus people.jsonl)

Agentenversand (Grundgerüst, pro Batch in einer Nachricht wiederholen):

Agent(
  description: „Personenanreicherung Batch aa“,
  prompt: ,
  subagent_type: „general-purpose“
)
Agent(
  description: „Personenanreicherung Batch ab“,
  prompt: ,
  subagent_type: „general-purpose“
)
… bis zu 6 pro Nachricht

Nachdem alle Unteragenten zurückgekehrt sind, überprüfe, ob die Personen-Dateien vorhanden sind:

ls {OUTPUT_DIR}/people/*.md | wc -l
# Sollte dem Ergebnis von „wc -l _people_to_enrich.jsonl“ entsprechen

Schritt 9: Bericht erstellen

Erstellen Sie den nach Unternehmen gruppierten HTML-Index, alternative Ansichten und die CSV-Datei mit einem einzigen Befehl:

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

Dadurch wird Folgendes generiert:

  • {OUTPUT_DIR}/index.html – Personen nach Unternehmen gruppiert, sortiert nach dem ICP-Score des Unternehmens (wird im Browser geöffnet)
  • {OUTPUT_DIR}/people.html – filterbare Referentenliste (alternative Ansicht)
  • {OUTPUT_DIR}/companies.html – ICP-sortierte Unternehmenstabelle mit Teilnehmern
  • {OUTPUT_DIR}/results.csv – für Kaltakquise vorbereitete Tabelle

Präsentieren Sie anschließend eine Zusammenfassung im Chat:

## Event-Prospektion abgeschlossen — {Veranstaltungsname}

- **Gesamtzahl der extrahierten Referenten**: {Anzahl}
- **Eindeutige Unternehmen**: {Anzahl}
- **ICP-Übereinstimmungen (Score ≥ {Schwellenwert})**: {Anzahl}
- **Angereicherte Referenten**: {Anzahl}
- **Score-Verteilung** (Unternehmen):
  - Starke Übereinstimmung (8–10): {Anzahl}
  - Teilweise Übereinstimmung (5–7): {Anzahl}
  - Schwache Übereinstimmung (1–4): {Anzahl}
- **Bericht im Browser geöffnet**: {OUTPUT_DIR}/index.html

Zeige die 5 besten Personenkarten als Markdown-Tabelle an, sortiert nach dem ICP-Wert des Unternehmens, und biete dann Folgendes an:

  • Passen Sie den Parameter ` --icp-threshold` an und führen Sie die Schritte 6–9 erneut aus
  • Die CSV-Datei in ein CRM exportieren
Auf GitHub ansehen
---
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 installieren

Laden Sie die Skill-Dateien herunter und entpacken Sie sie in Ihr Verzeichnis „.claude/skills/“.

ZIP herunterladen

Klonen Sie das Repository und kopieren Sie die Skill-Dateien in Ihr Projekt.

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

Kopieren Kopieren
Schnelle Einrichtung: Kopiere den Skill-Ordner nach .claude/skills/ Claude erkennt den Skill automatisch und nutzt ihn.
Repository browserbase/skills

Ähnliche Skills

multica-creating-agents
Zeit aktualisiert 12. August 2026
tilemaps
Zeit aktualisiert 4. August 2026
v4-new-features
Zeit aktualisiert 4. August 2026
pixijs-application
Zeit aktualisiert 4. August 2026
OR