---
name: closecrm-enrich-manual-lead-recruiting
description: >-
  Reichert einen manuell im Close-CRM angelegten Lead (eine Firma mit offener Stelle) end-to-end
  fuer den Recruiting-Anruf an: recherchiert ALLE Personen der Firma (Team-Seite, Impressum, Web,
  LinkedIn-"People"-Seite via Playwright), legt sie als Kontakte am Lead an (Entscheider zuerst nach
  Firmengroessen-Logik: GF/Prokura bei kleinen, Personalleiter/Betriebsleiter/Werksleiter bei mittleren
  Firmen), und schreibt eine Anruf-Briefing-Notiz inkl. der gesuchten Stelle. Nutze
  diesen Skill IMMER wenn eine Close-Lead-URL (app.close.com/lead/...) oder Lead-ID kommt mit:
  "Lead anreichern", "alle Personen/Mitarbeiter bei dieser Firma finden", "Kontakte fuer den Anruf
  anlegen", "Lead fuer den Call vorbereiten", "wer entscheidet bei dieser Firma", "Entscheider
  eintragen", "komplette Research fuer diesen Lead". Fuer Recruiting-Outreach, kundeneigenes
  Close-CRM. Setup (Close-MCP + Playwright + Claude Code) siehe references/setup-guide.md.
---

<!-- SIZE CONSTRAINT: This skill follows the 500-line limit.
If this file approaches 500 lines during edits, DO NOT just keep adding content.
Instead, move detailed sections into references/:
  closecrm-enrich-manual-lead-recruiting/
  ├── SKILL.md          ← core workflow + pointers, stays under 500 lines
  └── references/
      ├── priority-taxonomy.md
      ├── close-api-gotchas.md
      ├── note-template.md
      ├── recruiting-positions.md
      ├── linkedin-people-page.md
      └── setup-guide.md
SKILL.md should then contain clear pointers: "For X, read references/<file>.md"
-->

# closecrm-enrich-manual-lead-recruiting - Close-CRM-Lead fuer den Recruiting-Anruf anreichern

**Ziel:** Aus einem manuell im Close-CRM angelegten Lead (eine Firma mit offener Stelle) heraus ALLE
Personen recherchieren die bei der Firma arbeiten, sie als Kontakte am Lead anlegen (die fuer das
Recruiting-Gespraech wichtigsten zuerst), bestehende Kontakte ergaenzen, und eine Research-Notiz mit
Anruf-Briefing hinterlegen. So kann der Lead danach sauber angerufen werden - mit dem richtigen
Ansprechpartner und dem Wissen, welche Stelle die Firma offen hat.

**Fuer wen:** Recruiting-Firmen (Performance-Recruiting). Der Skill laeuft im **kundeneigenen Close-CRM** auf
der eigenen Maschine. Er verkauft ein **System zur Mitarbeitergewinnung** - nie "Personalvermittlung".

## Voraussetzungen (einmalig einrichten)

Bevor dieser Skill laeuft, muessen drei Dinge stehen (volle Klick-Anleitung: `references/setup-guide.md`):

1. **Claude Code installiert** und in einem Terminal gestartet.
2. **Close-CRM-MCP eingerichtet** mit dem eigenen Close-API-Key (Server-Name `close-crm`, Env
   `CLOSE_API_KEY`). Dann stehen Tools `mcp__close-crm__get_lead`, `..._create_contact`,
   `..._update_contact`, `..._create_note`, `..._get_custom_fields`, `..._get_activities` bereit.
3. **Playwright-MCP eingerichtet** (`@playwright/mcp --extension`), verbunden mit dem eigenen,
   bei LinkedIn eingeloggten Chrome. Das ist der Kern der Personen-Recherche (siehe Schritt 3b).

> Wenn die Tool-Namen einen anderen Server-Prefix haben (z.B. der MCP heisst nicht `close-crm`),
> denselben Prefix konsistent verwenden. Fehlt der Close- oder Playwright-MCP: `references/setup-guide.md`.

## Pre-Flight (Pflicht, bevor ein Tool laeuft)

1. **Lead-ID extrahieren** aus der URL: `app.close.com/lead/<LEAD_ID>/` → `lead_...`. Kommt nur ein
   Firmenname statt URL: Lead per Name suchen (`search_leads`) oder nach der Lead-URL fragen.
2. **Lead lesen** (Schritt 1) und pruefen, dass es die richtige Firma ist, bevor irgendetwas
   geschrieben wird.
3. **Research inline machen, nicht per Subagent** - WebFetch/WebSearch direkt nutzen, sparsam.

## Workflow

### Schritt 1: Lead lesen und Firma identifizieren

`get_lead(lead_id)`. Daraus ziehen:
- **Firmenname** und **Domain** (`url`, z.B. `http://www.mustermann-kfz.de`).
- **Bestehende Kontakte** (`id`, `name`, `title`, `emails`, `phones`, custom fields). Die merkst du
  dir: bestehende Kontakte werden NIEMALS geloescht, nur ggf. ergaenzt.
- **MA-Hinweis** in `description` (z.B. "85 MA") - wichtig fuer die Entscheider-Logik (Schritt 4).
- **Offene Stelle / Anlass** falls im Lead vermerkt (welche Position die Firma sucht).

Wenn `get_lead` zu gross fuer den Context ist (in eine Datei gespeichert), per `jq`/`grep` auf die
Datei zugreifen statt alles zu lesen.

### Schritt 2: Team recherchieren

Ziel: jede echte Person mit Name + Rolle. Reihenfolge der Quellen:

1. **Homepage** WebFetchen, Navigation nach Team-Seite absuchen ("Team", "Ueber uns", "Unternehmen",
   "Karriere", "Kontakt", "Ansprechpartner") und Kontaktdaten (Zentrale, Mail, Adresse) abgreifen.
2. **Team-/Ansprechpartner-Seite** WebFetchen mit Prompt: "List EVERY team member, full name + exact
   job title, do not summarize or skip anyone."
3. **Impressum** WebFetchen: Geschaeftsfuehrer, Inhaber, Adresse, zentrale Telefonnummer,
   Handelsregister, USt-IdNr.
4. **WebSearch** fuer Firmen-Eckdaten (Mitarbeiterzahl, Standorte, Branche, Gruppenzugehoerigkeit,
   Gruendungsjahr) - relevant fuer die Entscheider-Logik nach Firmengroesse.

**Scherz-/Nicht-Personen rausfiltern.** Deutsche Firmen-Seiten listen manchmal Bueroh unde oder
Maskottchen mit Wortspiel-Titeln ("Feel-Good-Manager (Hund)"). Das sind KEINE Mitarbeitenden - nicht
anlegen, im Report ausweisen.

**Nicht extrapolieren** (Hard-Rule): jede Person stammt aus der Live-Team-Seite/Impressum/LinkedIn,
nie aus Annahmen. Keine Personen "dazudichten".

### Schritt 3: E-Mail-Muster und Telefon ableiten

- **E-Mail-Muster** aus bestehenden Kontakten ableiten (z.B. zwei Kontakte mit
  `vorname.nachname@domain` → Muster bestaetigt). Fuer neue Personen nach dem Muster bilden,
  Bindestrich-Namen beibehalten, Umlaute wie auf der Seite. **Immer als "Muster, nicht einzeln
  verifiziert" kennzeichnen** (in Notiz und Report). Fuer reines Anrufen egal, vor E-Mail-Versand
  verifizieren.
- **Telefon**: die zentrale Nummer aus Impressum/Kontaktseite als `office`-Phone auf jeden neuen
  Kontakt setzen (Click-to-Call). Direkte Durchwahlen/Mobil nur wenn echt belegt.

### Schritt 3b: LinkedIn-URLs finden + VALIDIEREN (Playwright-"People"-Seite IMMER)

Die LinkedIn-Company-**"People"-Seite** ist die vollstaendige, definitive Personenquelle - nur ueber
einen echten eingeloggten Browser erreichbar (Login-Wall), darum **Playwright**. WebSearch ist nur
Ergaenzung. Volle Mechanik (Slug finden, kostenoptimiertes Extrahieren, Pagination, Team-Match):
**`references/linkedin-people-page.md`** - vor dem ersten Browser-Call lesen.

Kurzfassung:
1. **Firmen-Slug** via 1 WebSearch (`"<firma>" linkedin company`).
2. **`browser_navigate`** auf `https://www.linkedin.com/company/<slug>/people/`.
3. **Kostenoptimiert extrahieren** per `browser_evaluate` (nur Name + `/in/`-href + Headline pro
   Karte) - NIE `browser_snapshot` der ganzen Seite (10-40k Tokens; JS-Extract ~1-3k).
4. **Pagination**: "Show more results" + scrollen bis alles geladen.
5. **Gegen die Team-Seite matchen**: nur echte Team-Mitglieder uebernehmen. People-Page-Treffer die
   NICHT zur Firma gehoeren (andere Firma, job-suchend, Werkstudent eines Konzerns) NICHT anlegen.

**Validierung (Pflicht, sonst NICHT anhaengen):** URL gilt als bestaetigt wenn (a) aus der
People-Seite (Firmen-Zugehoerigkeit per Definition belegt, Name gegen Team-Seite matchen), oder
(b) WebSearch-Titel zeigt Name UND Firma, oder (c) eindeutig seltener Name + passende Rolle/Region.
Sonst: unbestaetigt → NICHT anhaengen, im Report als "nicht eindeutig gefunden" ausweisen.

**Speicherung:** LinkedIn-URL ins dedizierte LinkedIn-Custom-Field (nicht in den generischen
`urls`-Array). Field-ID dynamisch ermitteln: bestehenden Kontakt mit LinkedIn-URL lesen und dessen
`custom.cf_...`-Key uebernehmen, ODER `get_custom_fields(type:"contact")` nach "LinkedIn" durchsuchen.
Setzen via `update_contact(contact_id, {"custom.cf_<id>": "<url>"})`. URL auf
`https://www.linkedin.com/in/<slug>` normalisieren (de.-Prefix → www.).

**Playwright nicht verfuegbar?** Dann auf WebSearch je Person zurueckfallen (Stufe c oben) und im
Report klar nennen, dass die LinkedIn-People-Seite nicht gezogen wurde (Coverage-Luecke). Kein
Apify / kein bezahltes Scraping ohne Ruecksprache.

### Schritt 4: Prioritaets-Reihenfolge festlegen (Recruiting-Entscheider-Logik)

Close zeigt Lead-Kontakte FIX nach `date_created` (aelteste zuerst). Es gibt **kein** Reorder-Feld
und **kein** `delete_contact` in der MCP. Konsequenz: **Kontakte gleich in der richtigen Reihenfolge
anlegen** (sequenziell), dann steht das Panel von Anfang an sortiert.

**Wer ist beim Recruiting-Anruf der Entscheider? Haengt von der Firmengroesse ab** (Schritt 1 MA-Zahl):

- **Kleine Firma (< 100 MA):** Geschaeftsfuehrer / Inhaber / Prokurist zuerst - die entscheiden ueber
  Personalbudget direkt.
- **Mittlere Firma (100-2.000 MA):** Personalleiter / HR-Leiter zuerst, dann Betriebsleiter /
  Werksleiter / Standortleiter, dann kaufmaennische Leitung.
- **Fachbereichsleiter** der zur offenen Stelle passt (z.B. Werkstattleiter bei KFZ-Stellen,
  Bauleiter bei Bau-Stellen) ist immer ein starker Zweit-Ansprechpartner.

Volle Rang-Tabelle + Titel-Mapping: `references/priority-taxonomy.md`. Bei bestehenden Kontakten mit
Aktivitaets-Historie: **niemals loeschen/umsortieren**, nur die NEU anzulegenden Personen optimieren.

### Schritt 5: Kontakte anlegen (in Prioritaets-Reihenfolge, sequenziell)

Fuer jede neue Person, in Prioritaets-Reihenfolge, EINZELN/sequenziell (damit `date_created` die
Reihenfolge ergibt):

`create_contact(lead_id, name, title, emails:[{email, type:"office"}], phones:[{phone:<Zentrale>, type:"office"}])`

- Personen die schon als Kontakt existieren NICHT doppelt anlegen. Bestehende per `update_contact`
  ergaenzen wenn Felder leer sind (z.B. fehlender `title`).
- Validierte LinkedIn-URLs (Schritt 3b) ins LinkedIn-Custom-Field schreiben (nicht in `urls`).
  `update_contact` ueberschreibt nur mitgegebene Felder; andere bleiben erhalten.
- Sequenziell anlegen (ein Call nach dem anderen) fuer garantierte Panel-Sortierung. Parallele
  Calls haben keine garantierte Reihenfolge.

### Schritt 6: Research-Notiz mit Anruf-Briefing

`create_note(lead_id, note_html)`. **note_html MUSS in `<body>...</body>` gewrappt sein** (Close
validiert gegen XHTML-Schema, einzelnes Root-Element). `<br/>` selbstschliessend, `&` als `&amp;`.
Erlaubt: h1-h6, p, ul, ol, li, strong, em, a, br, table. Vorlage: `references/note-template.md`.

Struktur (Recruiting-fokussiert):
- Ueberschrift + Quelle + Stand-Datum
- Firmen-Eckdaten (Name, Branche, Standort, Mitarbeiterzahl, Zentrale, Register)
- **Empfohlener Ansprechpartner fuer den Recruiting-Call** (mit Begruendung: Rolle + warum er der
  Personal-Entscheider ist, gegeben die Firmengroesse)
- **Offene Stelle / Recruiting-Anlass**: welche der besetzbaren Positionen die Firma
  sucht (Abgleich gegen `references/recruiting-positions.md`)
- Gesamtes Team nach Funktion gruppiert
- Hinweise (E-Mail-Muster unverifiziert, Telefon = Zentrale, Nicht-Personen nicht angelegt)

### Schritt 7: Report

Tabelle aller Kontakte (#, Name, Rolle, neu/bestand), Entscheider hervorheben, Zentrale + beste
Direktnummer nennen, die Caveats ehrlich nennen (Muster-Mails, keine Durchwahlen, ggf. fehlende
People-Page). Lead-Link mitgeben.

## Recruiting-Kontext (fuer Notiz + Ansprache)

- Die Recruiting-Firma verkauft ein **System zur Mitarbeitergewinnung** (Ads + Bewerber-Datenbank), NICHT
  "Personalvermittlung" oder "Zeitarbeit". Das Anti-Frame "Personaldienstleister / lassen Sie uns
  sprechen" vermeiden.
- Ton: **Siezen**, Hochdeutsch, konservativ, keine Emojis.
- Telefon ist Sekundaerkanal (Nummern-Qualitaet ~60%) - das Briefing zielt auf den richtigen
  Entscheider, nicht auf Masse.
- Die besetzbaren Positionen (KFZ/NFZ, Elektro/Energie, Leitungs-/Netzbau,
  Metall/Industrie, Bau/Handwerk, Logistik/Fahrer, kaufmaennisch): Snapshot in
  `references/recruiting-positions.md` (periodisch aktualisieren, kein Live-Abruf auf Kundenmaschine).

## Harte Gotchas

Details: `references/close-api-gotchas.md`. Die wichtigsten:
- **Close-Notiz braucht `<body>`-Root** - ohne: 400 "expected to start with a <body> tag".
- **Kein Reorder-API, kein MCP-Delete** - Reihenfolge nur durch Anlege-Reihenfolge steuerbar.
- **Bestehende Kontakte mit Historie NIEMALS loeschen.**
- **Close-API-Key** nur via `jq` aus `~/.claude/.mcp.json` parsen, NIEMALS echo/print.

## Prior art

Recherche auf skills.sh + agentskills.io (Genre "CRM/lead enrichment, contact research, call-prep"):
- **Grundwerk-intern `closecrm-manually-enrich-full-lead`** - die direkte Basis dieses Skills (gleicher
  Zweck, Grundwerk-eigenes Close, Tom-betrieben). Dieser Skill ist die Recruiting-Spezialisierung
  davon: kundeneigenes Close, Recruiting-Entscheider-Logik nach Firmengroesse, self-contained
  (eigene references, da der Kunde keinen Zugriff auf Grundwerk-interne Skills/DB hat).
- **Amplemarket `pre-call-research-brief` / `enrich-and-score-lead` / `competitive-account-research`**
  (github.com/amplemarket/skills) - Genre-Nachbarn, aber vendor-locked an Amplemarket+HubSpot,
  read-only bzw. nur HubSpot-Write, kein Close-Write, kein Browser-Research. **Borrow** ohne
  Code-Uebernahme: die Seniority-Scoring-Idee (→ Prioritaets-Taxonomie) und die strukturierte
  Briefing-/Talking-Points-Vorlage (→ Notiz-Template).
- **Entscheidung: Build** (mit den zwei Borrows oben). Fork eines Amplemarket-Skills haette mehr Umbau
  als Neubau gekostet (kompletter Daten-Layer-Tausch); reines Borrow reicht nicht, da der
  differenzierende Kern (Close-Write + Playwright-People-Page) Eigenlogik ist.

## Was dieser Skill NICHT tut

- Kein Bulk-LinkedIn-Scraping / kein bezahltes Scraping ohne Ruecksprache.
- Kein automatischer E-Mail-Versand. Nur CRM-Anreicherung fuer den Anruf.
- Keine Massen-Lead-Anlage. Ein Lead pro Lauf, sorgfaeltig recherchiert.
