CommunityRédaction et éditiongithub.com

outreachmagic/lead-enrich

Recherche de personnes pour les agents IA. Interroge Serper pour obtenir LinkedIn, le domaine de l'entreprise et le site web. S'associe à Outreach Magic pour un déduplication économique.

Qu'est-ce que lead-enrich ?

Cette compétence permet aux agents IA de mener des recherches approfondies sur des prospects (nom + entreprise) en utilisant l'API Serper.dev pour des recherches Google structurées. Elle extrait des informations clés comme le profil LinkedIn, le domaine et le site web de l'entreprise, en exploitant le modèle de raisonnement intégré de l'agent, sans nécessiter d'API LLM externe. La compétence fonctionne de manière autonome avec une simple clé Serper, mais s'intègre particulièrement bien à Outreach Magic (OM) pour une déduplication intelligente : avant toute dépense de crédits Serper, elle vérifie si le prospect possède déjà un LinkedIn et un email dans la base OM, évitant ainsi des recherches inutiles. Pour les cas où seul l'email est connu, des recherches LinkedIn ciblées sont lancées (1 à 2 crédits Serper), tandis que les correspondances de nom dans des entreprises différentes sont marquées comme « ambiguës » pour éviter de gaspiller des appels API. La compétence prend en charge l'enrichissement par lots via CSV/JSON avec une limite de 50 personnes par exécution, et propose un workflow clair en trois phases : vérification de déduplication (zéro crédit), recherche Serper (2 à 4 requêtes par personne), et extraction par le modèle de l'agent. Elle intègre également un mécanisme de balisage des tentatives (`serper_attempted`) pour éviter les doubles traitements, et peut déléguer la recherche d'emails à la compétence `email-finder` après enrichissement. La transparence est assurée en affichant les requêtes Serper effectuées, leur coût en crédits, et les résultats sauvegardés.

Compatible avec✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add outreachmagic/lead-enrich

Installed? Explore more Rédaction et édition skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Lead Enrich

Recherchez une personne (nom + entreprise) en utilisant la recherche Google Serper.dev. Utilise le modèle intégré de l'agent pour l'extraction. Aucune API LLM externe nécessaire.

Fonctionne de manière autonome — juste une clé Serper. S'associe à Outreach Magic pour une déduplication économique (évite Serper lorsque les leads ont déjà LinkedIn/email) et un stockage persistant entre les sessions.

Économie de crédits (avec OM) : vérifie d'abord dans outreachmagic. Si le lead a déjà LinkedIn + email dans la même entreprise, zéro crédit Serper dépensé. LinkedIn sans email évite Serper — utilisez email-finder pour trykitt. Les enregistrements avec uniquement un email déclenchent toujours des recherches LinkedIn (1 à 2 crédits Serper). Les correspondances de nom dans une entreprise différente renvoient ambiguous pour ne pas gaspiller les API.

Configuration

Autonome (sans OM)

Juste une clé Serper. Exécutez serper-search directement. Les résultats s'affichent en JSON.

CléPour
SERPER_API_KEYserper.dev — API de recherche Google
python3 scripts/enrich.py serper-search --query '"Acme Corp" site web officiel'
python3 scripts/enrich.py serper-search --query 'site:linkedin.com/in Jane Doe Acme Corp'
# → redirigez les résultats vers votre modèle pour extraction, ou utilisez serper-format

Définissez SERPER_API_KEY dans votre environnement ou via ~/.hermes/skills/lead-enrich/config.json.

Avec Outreach Magic (déduplication + sauvegarde)

Ajoute une déduplication préalable (ignorer les leads déjà présents dans OM) et sauvegarde l'enrichissement structuré dans votre pipeline SQLite local. Nécessite la compétence outreachmagic avec pipeline.py login.

CléPour
Toutes les clés autonomes ci-dessus +
OUTREACHMAGIC_AGENT_KEYConnexion OM via pipeline.py login
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"        # 0 crédits
python3 scripts/enrich.py batch-check --workspace W input.json # déduplication par lots

Enregistrez votre clé Serper dans le portail Outreach Magic → Paramètres → Clés API, puis exécutez pipeline.py sync-secrets. Vérifiez avec enrich.py config (serper_api_key_source devrait être agent_secrets).

3. Recherche d'email (compétence email-finder)

La recherche d'email ne fait pas partie de lead-enrich v2+. Installez email-finder avec outreachmagic en suivant le guide d'installation de la plateforme. Ou installez-le de manière autonome via npx skills add outreachmagic/email-finder.

Après que l'enrichissement Serper a sauvegardé company_domain, exécutez :

python3 ~/.hermes/skills/email-finder/scripts/email_finder.py find --name "Jane Doe" \
  --domain acme.com --linkedin "https://linkedin.com/in/janedoe" --save

Consultez references/email-finder.md et la documentation de la compétence email-finder.

Résumés d'espace de travail (zéro crédit Serper) : après avoir sauvegardé les leads, utilisez outreachmagic avec workspace summary --workspace <slug> --json pour obtenir le comptage des tags et les acceptations de connexion LinkedIn par expéditeur. Pour les grands espaces de travail (>2 000 leads), ajoutez --tags-only pour un comptage plus rapide. Base de données locale uniquement — l'extraction est facultative.

Workflows courants

L'utilisateur ditVous faites
"Recherchez cette personne"Recherche Serper → sauvegarde via import-profiles
"Enrichissez mon CSV"batch-check / importation → enrichir les champs manquants → sauvegarder dans OM
"Trouvez aussi son email"Après enrichissement, transmettez à email-finder

CSV Sales Nav / Vayne : utilisez outreachmagic import-profiles --file … (détection automatique des colonnes).

Workflow CSV / liste de récompenses (recommandé pour 10 personnes et plus)

Les chemins comme outreachmagic/imports/awards.csv sont relatifs à votre répertoire d'espace de travail (où l'agent exécute la commande), pas au dossier d'installation de la compétence.

# 0 crédits — dédupliquez d'abord l'intégralité du fichier (marque automatiquement serper_attempted sur les lignes complètes)
python3 scripts/enrich.py batch-check --workspace your_workspace outreachmagic/imports/awards.csv

# Réexécutez la déduplication en ignorant les leads déjà marqués serper_attempted
python3 scripts/enrich.py batch-check --workspace your_workspace --skip-tagged outreachmagic/imports/awards.csv

# Serper uniquement pour les lignes qui ont besoin de LinkedIn/domaine (ignore team_award, exists_linkedin_*, skipped_serper_attempted)

# Après la recherche — corrigez le titre/le secteur (0 crédits Serper)
python3 scripts/enrich.py backfill --fields title,industry --workspace your_workspace outreachmagic/imports/patch.csv

batch-check accepte .json ou .csv. backfill nécessite email ou linkedin par ligne ; utilise des import-profiles par lots via companion_common (200 lignes/lot, jusqu'à 300 s/lot ; remplit les champs vides ; ajoutez --overwrite pour remplacer).

Quand l'utiliser

  • L'utilisateur dit "recherchez cette personne" / "trouvez Jane Doe chez Acme"
  • L'utilisateur souhaite enrichir une liste de prospects avant prospection
  • L'utilisateur demande "avons-nous déjà ce lead ?" avant de faire des recherches
  • L'utilisateur fournit un CSV/JSON de noms et d'entreprises à enrichir en masse
  • L'utilisateur mentionne Serper, l'enrichissement de leads ou la recherche de personnes

Règles de comportement de l'agent (Importantes)

  1. Déduplication d'abord (avec OM). Avant tout appel API Serper, exécutez enrich.py check. Si le lead a LinkedIn + email dans la même entreprise, ignorez complètement Serper. Si LinkedIn existe mais pas d'email, ignorez Serper et proposez email-finder lorsque l'utilisateur souhaite une adresse. Ne dépensez jamais de crédits Serper pour des leads déjà complets dans outreachmagic. Autonome : ignorez la vérification — exécutez serper-search directement.
  2. Serper uniquement. Préférez enrich.py serper-search --query "..." (HTTP de la bibliothèque standard, clé depuis la configuration/l'environnement). Ou utilisez curl avec $SERPER_API_KEY — n'incorporez jamais la clé dans les journaux de discussion. Ne grattez jamais Google ou LinkedIn directement.
  3. Modèle intégré uniquement. Vous (l'agent) extrayez le JSON des résultats Serper. Pas d'API LLM externes (pas de Gemini, pas d'OpenAI) — votre propre raisonnement est le moteur d'extraction.
  4. Recherche complète avant sauvegarde. Effectuez d'abord l'ensemble de la chaîne de recherche, puis sauvegardez une seule fois.
  5. Sauvegarde via outreachmagic (avec OM). Utilisez import-profiles pour les leads avec LinkedIn. Ajoutez toujours serper_attempted aux tags lors de la sauvegarde (inclus automatiquement dans la sortie de map-to-om). Pour les leads sans LinkedIn mais avec un lead_id connu, marquez le tag via stamp-attempted ou import-profiles avec id + tags — ne vous fiez pas uniquement aux notes. Pour les vérifications de déduplication en lecture seule, utilisez pipeline.py query ou enrich.py check — jamais de INSERT/UPDATE bruts. N'exécutez jamais les deux chemins de sauvegarde pour la même personne. Autonome : sauvegardez la sortie JSON dans un fichier — pas besoin d'OM.
  6. Marquage après enrichissement (avec OM). Chaque lead qui passe par Serper doit recevoir serper_attempted lors de la sauvegarde. Empêche le retraitement lors des exécutions futures.
  7. Vérification du tag avant Serper (avec OM). Avant de dépenser des crédits Serper, vérifiez la présence de serper_attempted (via enrich.py check --skip-tagged ou skip_reason dans la sortie de la vérification). S'il est présent et que LinkedIn est toujours vide, ignorez-le, sauf si l'utilisateur souhaite explicitement une nouvelle tentative (par exemple, données obsolètes de plus de 30 jours).
  8. Transparence. Montrez quelles requêtes Serper ont été exécutées, le niveau de confiance et ce qui a été sauvegardé. L'utilisateur doit voir exactement où ses crédits ont été dépensés.
  9. Traitement par lots judicieusement. Limitez à 50 personnes par exécution. Pour les listes CSV/de récompenses, exécutez d'abord batch-check une fois sur l'intégralité du fichier (JSON ou CSV) avant tout Serper. Traitez Serper uniquement pour les statuts qui ont besoin de LinkedIn/domaine. Ignorez les lignes team_award, exists_linkedin_email et skipped_serper_attempted.
  10. Recherche d'email — utilisez email-finder. Après que l'enrichissement a sauvegardé company_domain, transmettez à email-finder (email_finder.py find --save). Consultez references/email-finder.md. Ne fabriquez ni ne devinez jamais d'emails dans cette compétence.

Démarrage rapide

# Une seule personne (le plus courant)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# → si "not_found", procédez avec le pack de recherche Serper ci-dessous

# Avec espace de travail (associe le lead à votre pipeline d'espace de travail)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"

# Par lots depuis un JSON ou CSV (exécutez ceci avant Serper sur les listes)
python3 scripts/enrich.py batch-check --workspace your_workspace outreachmagic/imports/people.json
python3 scripts/enrich.py batch-check --workspace your_workspace --skip-tagged outreachmagic/imports/awards.csv

# Marquer serper_attempted après un échec de recherche LinkedIn (lorsque lead_id est connu)
python3 scripts/enrich.py stamp-attempted --workspace your_workspace --lead-ids 42,43 \
  --notes "Aucun LinkedIn trouvé via Serper"

# Remplir a posteriori le titre/secteur sur les leads existants (linkedin ou email requis)
python3 scripts/enrich.py backfill --fields title,industry outreachmagic/imports/patch.csv

# Mettre à jour la compétence en toute sécurité depuis une version GitHub (vérification par somme de contrôle)
python3 scripts/enrich.py update --check
python3 scripts/enrich.py update

update vérifie les sommes de contrôle SHA256 à partir de update-manifest.json avant de remplacer les fichiers. Si les sommes de contrôle sont manquantes ou ne correspondent pas, la mise à jour est abandonnée.

Workflow de base

Phase 1 — Vérification de déduplication (0 crédits)

Pour chaque personne, exécutez :

# Sans espace de travail (recherche dans toute l'organisation)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"

# Avec espace de travail (limité à votre pipeline d'espace de travail)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"

Sortie par personne :

StatutSignificationAction
exists_linkedin_emailMême entreprise, LinkedIn + emailIgnorer Serper et les API d'email
exists_linkedin_no_emailMême entreprise, LinkedIn, pas d'emailIgnorer Serper → email-finder si l'utilisateur souhaite un email
exists_no_linkedin_emailMême entreprise, email, pas de LinkedInRequêtes Serper LinkedIn uniquement
exists_no_linkedinMême entreprise, aucun des deuxRequêtes Serper LinkedIn uniquement
skipped_serper_attemptedA le tag serper_attempted, pas de LinkedInIgnorer Serper — déjà essayé
ambiguousCorrespondance de nom, désaccord d'entrepriseExécuter le pack Serper complet — ne pas ignorer
not_foundAucune correspondanceExécuter le pack de recherche Serper complet
team_awardLigne d'équipe/groupe (pas un individu)Ignorer Serper — taguer team_award, ajouter une note de contact
dedup_disableddedup_before_search: false dans la configurationExécuter Serper comme demandé

La sortie de la vérification inclut tags et éventuellement skip_reason (has_linkedin ou skipped_serper_attempted). Utilise batch-lead-lookup (local, zéro crédit Serper).

Phase 2 — Pack de recherche Serper

Exécutez uniquement pour les personnes qui en ont besoin. 2 à 4 recherches par personne selon la qualité des résultats :

Estimation du budget de crédits Serper

  • Minimum par personne : 0 crédit Serper (exists_linkedin_email).
  • Chemin courant : 2 crédits (2a entreprise stricte + 2c profil LinkedIn).
  • Maximum absolu par personne : 4 crédits lorsque tous les replis sont nécessaires (2a + 2b + 2c + 2e).
  • Formule par lots : min=0, max=4*N où N est le nombre de personnes dans l'exécution.
  • Exemple de limite par lots : avec N=50, le maximum absolu est de 200 crédits (pire cas).

2a. Découverte d'entreprise — stricte (toujours)

Préféré (pas de clé dans l'historique du shell) :

python3 scripts/enrich.py serper-search --query '"Acme Corp" site web officiel' --label company_discovery_strict

Ou réessayez avec une requête plus simple :

python3 scripts/enrich.py serper-search --query 'Acme Corp site web' --label company_discovery_broad

2b. Découverte d'entreprise — large (conditionnel)

Exécutez uniquement si 2a ne renvoie aucun résultat organique avec un lien http:// ou https:// :

python3 scripts/enrich.py serper-search --query 'Acme Corp site web officiel' --label company_discovery_broad

(Même modèle, nom d'entreprise non cité.)

2c. Profil LinkedIn (toujours)

Construisez la requête (entreprise non citée — correspond aux noms d'employeurs variants dans les extraits) :

site:linkedin.com/in {Prénom Nom} {jusqu'à 5 mots du rôle} {Nom de l'entreprise}

Exemple :

python3 scripts/enrich.py serper-search \
  --query 'site:linkedin.com/in Jane Doe VP Marketing Acme Corp' \
  --label linkedin_profile

Phase 3 — Extraction par le modèle

Transmettez les résultats Serper formatés à vous-même (le modèle de l'agent) avec cette instruction système :

Vous êtes un assistant de recherche. Le message de l'utilisateur contient les résultats de recherche Google Serper.dev dans des sections étiquetées. Vous n'avez PAS de recherche web en direct — utilisez uniquement les blocs collés.

Tâche : pour UNE personne spécifique dans UNE entreprise spécifique, extrayez :
- company_domain : nom d'hôte enregistrable uniquement (pas de chemin, pas de www), ou chaîne vide
- company_website : URL complète https:// de la page d'accueil si prise en charge, ou chaîne vide
- linkedin_url : https://linkedin.com/in/… pour la personne nommée dans cette entreprise, ou chaîne vide
- confidence : high | medium | low
- note : explication facultative de l'ambiguïté ou des lacunes

Règles :
- Chaque URL non vide doit apparaître dans les blocs Serper (une normalisation mineure de la chaîne de requête est acceptable)
- Le nom sur LinkedIn peut différer de celui saisi (surnom vs nom légal) — faites correspondre la même personne + employeur
- Avant d'accepter `linkedin_url`, vérifiez la qualité de la correspondance :
  - Extrayez les tokens de prénom et de nom de `Nom complet : {full_name}` (ignorez la ponctuation)
  - Le résultat `/in/` choisi doit avoir *les deux* tokens présents dans le `titre` ou l'`extrait` du résultat
  - Si aucun résultat `/in/` ne satisfait l'exigence de token, renvoyez `linkedin_url` comme une chaîne vide et définissez `confidence` sur `low`
- Le site public de l'entreprise peut utiliser un nom de bannière différent de celui saisi — préférez les preuves officielles
- Lors de la résolution de `company_domain` :
  - Préférez `knowledgeGraph.website` lorsqu'il est présent
  - Rejetez les agrégateurs/registres courants (exemples : `naceweb.org`, `usnews.com`, `wikipedia.org`, `niche.com`, `facebook.com`, `instagram.com`, `twitter.com`)
  - Si `company_name` semble manquant ou correspond étroitement au nom de la personne, renvoyez une chaîne vide
- Ne fabriquez jamais d'URL ou de slugs

Répondez UNIQUEMENT avec un seul objet JSON (pas de délimiteurs de démarquage) :
{"company_domain":"","company_website":"","linkedin_url":"","confidence":"medium","note":""}

Utilisez ce modèle de message utilisateur :

### Personne cible
Nom complet : {full_name}
Rôle/titre déclaré : {stated_role}
Entreprise (telle que fournie) : {company_name}

### Résultats de recherche
{formatted_serper_sections}

### Tâche
Renvoie l'objet JSON décrit dans l'instruction système.

Analysez ensuite votre propre réponse : supprimez les délimiteurs de démarquage, extrayez l'objet JSON.

Repli de récolte LinkedIn : si linkedin_url est vide après extraction, analysez les résultats Serper bruts pour les URL /in/ dont le titre contient à la fois les tokens de prénom et de nom. Préférez les correspondances où l'extrait mentionne l'entreprise. S'il existe exactement un résultat candidat de haute qualité, incluez-le dans la sortie JSON avec confidence défini sur medium et une note explicative. Ne devinez jamais.

Phase 4 — Sauvegarde

Avec OM : utilisez import-profiles --profiles [...] ou import-profiles --file.

python3 ~/.hermes/skills/outreachmagic/pipeline.py import-profiles --profiles '[
  {"name":"Jane Doe","company":"Acme Corp","email":"[email protected]","linkedin":"https://linkedin.com/in/janedoe","company_domain":"acme.com","company_website":"https://acme.com","title":"VP Marketing","tags":["serper_attempted"]}
]'

Autonome : sauvegardez dans un fichier JSON.

python3 -c "
import json
result = {'company_domain':'acme.com','company_website':'https://acme.com','linkedin_url':'https://linkedin.com/in/janedoe','confidence':'high'}
with open('research_output.json', 'w') as f:
    json.dump(result, f, indent=2)
"

Toujours ajoutez serper_attempted aux tags.

Règles de l'agent : Résumé

S'il...Alors...
OM est configurécheck d'abord, dépensez des crédits uniquement si not_found ou ambiguous
exists_linkedin_no_email est renvoyéIgnorez Serper ; utilisez email-finder si l'utilisateur souhaite un email
exists_linkedin_email est renvoyéIgnorez complètement ; aucune dépense
ambiguous est renvoyéExécutez le pack complet ; c'est une nouvelle piste potentielle
not_found est renvoyéExécutez le pack complet ; nouvelle piste
Le modèle extrait des donnéesSauvegardez via import-profiles (avec OM) ou dans un fichier
Les recherches échouentMarquez avec serper_attempted ; ne réessayez pas automatiquement
L'utilisateur demande un email sur un lead avec LinkedIn mais sans emailTransmettez à email-finder ; ne cherchez pas de modèles dans cette compétence

Messages d'erreur et dépannage

  • Erreur batch-check — vérifiez les en-têtes CSV : name, company, email, linkedin, company_domain, company_website, title sont reconnus. D'autres en-têtes sont ignorés. Pour toute colonne nommée name et company, exécutez batch-check.
  • serper_api_key_source est agent_config — vous l'avez définie dans config.json. Dans OM, vous devez l'enregistrer dans le portail, puis exécuter pipeline.py sync-secrets.
  • Sauvegardes redondantes — la vérification de déduplication vérifie également serper_attempted dans le local. Si vous obtenez skipped_serper_attempted, le lead a déjà été traité.
  • La recherche LinkedIn échoue mais l'utilisateur insiste — exécutez une fois, puis marquez. Ne réexécutez pas sur le même lead sauf si l'utilisateur le demande explicitement (par exemple, "vérifiez à nouveau maintenant, son profil a peut-être été créé").

Rappels de style de code

  1. Utilisez enrich.py serper-search --query "..." pour les recherches Serper. Évitez curl pour les recherches complexes.
  2. Les chemins de fichiers CSV/JSON sont relatifs au répertoire de l'espace de travail, pas au dossier de la compétence.
  3. Lorsque vous traitez un CSV d'utilisateur, utilisez batch-check sur l'ensemble du fichier en premier, puis traitez ligne par ligne uniquement pour les statuts qui nécessitent Serper.
  4. Si l'utilisateur copie-colle du texte, écrivez-le d'abord dans un fichier, puis utilisez batch-check --workspace <slug> <fichier> avec table_name configuré sur batch_check_cache (détection automatique du format).

Workflow de bout en bout

Parcours complet avec OM :

# 1. Vérifier
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# → not_found, procéder

# 2a. Rechercher l'entreprise
python3 scripts/enrich.py serper-search --query '"Acme Corp" site web officiel' --label company_discovery_strict
# 2c. Rechercher le profil LinkedIn
python3 scripts/enrich.py serper-search --query 'site:linkedin.com/in Jane Doe Acme Corp' --label linkedin_profile

# 3. Extraire (échange avec le modèle avec instruction système)

# 4. Sauvegarder (avec OM)
python3 ~/.hermes/skills/outreachmagic/pipeline.py import-profiles --profiles '[
  {"name":"Jane Doe","company":"Acme Corp","linkedin":"https://linkedin.com/in/janedoe","company_domain":"acme.com","title":"VP Marketing","tags":["serper_attempted"]}
]'

Skills associés