Fills in missing data for inbound leads — researches the company, identifies the person's role and seniority, finds other stakeholders at the company, checks for existing CRM relationships, and updates the lead record. Produces enriched lead data ready for qualification or outreach. Tool-agnostic.
npx gooseworks install --all # then, in Claude Code, Cursor, or Codex: /gooseworks use the inbound-lead-enrichment skill
Takes inbound leads with incomplete data and fills in the gaps. Researches the company, identifies the person's role, finds other stakeholders at the company, and checks for existing relationships in CRM. Turns a bare email address into a full lead profile.
Load this composite when:
inbound-lead-qualification flags leads as insufficient_datainbound-lead-triage detects leads with missing company/title fields[Raw Leads] → Step 1: Assess Gaps → Step 2: Company Research → Step 3: Person Research → Step 4: Stakeholder Discovery → Step 5: Relationship Check → Step 6: Compile & Output
↓ ↓ ↓ ↓ ↓ ↓
Gap inventory Company profiles Person profiles Buying committee CRM/pipeline matches Enriched lead recordsOn first run, establish enrichment tool preferences.
{
"enrichment_tools": {
"company_research": {
"primary": "SixtyFour | Orthogonal | web-search",
"secondary": "web-search"
},
"person_research": {
"primary": "SixtyFour | Orthogonal | web-search",
"secondary": "web-search"
},
"stakeholder_finding": {
"primary": "SixtyFour | Orthogonal | web-search",
"secondary": "web-search"
}
},
"crm_source": {
"tool": "HubSpot | Salesforce | CSV | none",
"access_method": ""
},
"buyer_personas": [],
"enrichment_depth": {
"tier_1_leads": "deep",
"tier_2_leads": "deep",
"tier_3_leads": "standard",
"tier_4_leads": "minimal",
"untiered_leads": "standard"
}
}On subsequent runs: Load config silently.
For each lead, inventory what's known vs. unknown:
Required fields (must fill):
company_name — What company do they work for?company_domain — Company website domainperson_name — Full nameperson_title — Current job titleperson_email — Contact email (usually already have this from inbound)Valuable fields (fill if possible):
company_size — Employee count or rangecompany_industry — Industry classificationcompany_stage — Funding stage or maturitycompany_hq — Headquarters locationcompany_description — One sentence about what they doperson_seniority — IC, Manager, Director, VP, C-Level, Founderperson_department — Engineering, Sales, Marketing, etc.person_linkedin — LinkedIn profile URLperson_tenure — How long at current companyBonus fields (nice to have):
company_tech_stack — Known technologies usedcompany_recent_news — Any recent events (funding, launches, hires)person_background — Previous companies, educationperson_social_activity — Recent posts or engagement topicsFor each lead, classify the enrichment effort needed:
| Gap Level | Missing | Enrichment Needed | Cost |
|---|---|---|---|
| Minimal | 1-2 valuable fields | Quick web search | Free |
| Standard | Company or title missing | Web search + possible API lookup | Low |
| Deep | Multiple required fields missing | Multi-source research | Medium |
| Email-only | Only have an email address | Full research from scratch | High |
"Here's what's missing across your leads. [X] need deep enrichment, [Y] need standard, [Z] just need a quick lookup. Estimated cost: [amount]. Proceed?"
For each unique company in the lead list (deduplicate — don't research the same company twice for multiple leads):
From email domain (if company name is missing):
jane@acme.com → acme.com)Company profile research:
| Field | Primary Source | Fallback Source |
|---|---|---|
| Company name | Domain lookup | Web search |
| Description | Company website (homepage, about page) | LinkedIn company page, web search |
| Employee count | SixtyFour or Orthogonal, LinkedIn company page | Web search |
| Industry | LinkedIn company page, SixtyFour or Orthogonal | Infer from website content |
| Stage/Funding | SixtyFour or Orthogonal, news articles | Web search |
| HQ Location | LinkedIn company page, website | Web search |
| Tech stack | Job postings, BuiltWith | Web search |
| Recent news | Web search (last 90 days) | Twitter/social mentions |
Research depth by config:
Each company gets a company_profile block:
{
"company_name": "",
"company_domain": "",
"company_description": "",
"employee_count": "",
"employee_range": "",
"industry": "",
"sub_industry": "",
"stage": "",
"last_funding": "",
"hq_location": "",
"tech_stack": [],
"recent_news": [],
"research_sources": [],
"confidence": "high | medium | low"
}If the lead used a personal email (gmail, etc.):
company_unidentified — still proceed with person research if name is availableFor each lead, build a person profile:
From name + company (if title is missing):
Person profile research:
| Field | Primary Source | Fallback Source |
|---|---|---|
| Full name | Input data | LinkedIn profile |
| Current title | LinkedIn profile, SixtyFour or Orthogonal | Web search |
| Seniority level | Infer from title | LinkedIn profile |
| Department | Infer from title | LinkedIn profile |
| Tenure at company | LinkedIn profile | Web search |
| Previous companies | LinkedIn profile | Web search |
| Education | LinkedIn profile | Skip |
| LinkedIn URL | SixtyFour or Orthogonal, web search | Skip |
| LinkedIn headline | LinkedIn profile | Skip |
| Recent activity | LinkedIn posts (if scraper configured) | Skip |
Seniority inference rules:
IC_juniorIC_midIC_seniorManagerDirectorVPC_LevelFounderAdjust for company size:
Each lead gets a person_profile block:
{
"full_name": "",
"current_title": "",
"seniority_level": "",
"department": "",
"tenure_months": null,
"previous_companies": [],
"education": "",
"linkedin_url": "",
"linkedin_headline": "",
"recent_activity_summary": "",
"research_sources": [],
"confidence": "high | medium | low"
}For each company in the lead list, identify other relevant people — the buying committee.
Why this matters:
Who to find (based on buyer personas from config):
Process per company:
Depth control:
Each company gets a stakeholder_map:
{
"company": "",
"inbound_lead": {
"name": "",
"title": "",
"role_in_deal": "economic_buyer | champion | evaluator | user | unknown"
},
"stakeholders_found": [
{
"name": "",
"title": "",
"seniority": "",
"linkedin_url": "",
"email": "",
"role_in_deal": "",
"relationship_to_lead": "",
"confidence": "high | medium | low"
}
],
"buying_committee_completeness": "full | partial | minimal",
"recommended_multi_thread": ""
}If the inbound lead IS the economic buyer → stakeholders are supporting context If the inbound lead is a user/evaluator → finding the economic buyer is critical If the inbound lead is unknown → identifying their role determines the multi-threading strategy
For each lead AND each discovered stakeholder, check existing systems for prior relationships:
Check 1 — CRM (HubSpot, Salesforce, CSV):
Check 2 — Outreach history (outreach_log):
Check 3 — Company-level pipeline (companies table or CRM):
Check 4 — Signal history (signals table):
Check 5 — Mutual connections (if data available):
Each lead gets a relationship_context block:
{
"person_in_crm": true/false,
"person_crm_status": "",
"person_outreach_history": [
{
"date": "",
"channel": "",
"campaign": "",
"outcome": ""
}
],
"company_in_pipeline": true/false,
"company_deal_stage": "",
"company_deal_owner": "",
"company_signal_history": [],
"mutual_connections": [],
"relationship_summary": ""
}Merge all research into a single enriched record per lead:
{
"original_data": {},
"company_profile": {},
"person_profile": {},
"stakeholder_map": {},
"relationship_context": {},
"enrichment_metadata": {
"enrichment_depth": "deep | standard | minimal",
"fields_filled": X,
"fields_still_missing": [],
"sources_used": [],
"confidence_overall": "high | medium | low",
"enrichment_date": "",
"cost_incurred": ""
}
}Primary: Enriched CSV
Produce a CSV that extends the original lead data with all enriched fields:
| Original Fields | + Company Fields | + Person Fields | + Stakeholder Fields | + Relationship Fields | + Metadata |
|---|---|---|---|---|---|
| All input columns | company_description, employee_count, industry, stage, hq, tech_stack, recent_news | current_title, seniority, department, tenure, linkedin_url, headline | stakeholder_1_name, stakeholder_1_title, stakeholder_1_role, ... (up to 4) | in_crm, crm_status, in_pipeline, deal_stage, outreach_history_summary | enrichment_depth, confidence, fields_missing, sources_used |
Save to the current working directory or wherever the user prefers (e.g., leads/inbound-enriched-[date].csv).
Secondary: Enrichment Report
## Lead Enrichment Report: [Date]
### Summary
- **Total leads enriched:** X
- **Deep enrichment:** X leads (Tier 1-2)
- **Standard enrichment:** X leads (Tier 3)
- **Minimal enrichment:** X leads (Tier 4)
### Data Quality
- **Fully enriched** (all required + valuable fields): X leads
- **Mostly enriched** (all required, some valuable): X leads
- **Partially enriched** (some required fields still missing): X leads
- **Could not enrich** (insufficient starting data): X leads
### Company Research
- **Unique companies researched:** X
- **Companies already in CRM:** X
- **Companies with active deals:** X (flag for deal owner)
- **Companies with signal history:** X
### Stakeholder Discovery
- **Total stakeholders found:** X across Y companies
- **Economic buyers identified:** X
- **Champions identified:** X
- **Full buying committees mapped:** X companies
### Relationship Flags
- **Leads already in CRM:** X (update status, don't create duplicates)
- **Previously contacted leads:** X (check outreach history before re-engaging)
- **Companies with active deals:** X (coordinate with deal owner)
- **Warm intro paths found:** X
### Cost
- **Enrichment tool credits used:** [breakdown by tool]
- **Cost per lead:** [average]
### CSV saved to: [path]Lead with only an email, nothing else:
enrichment_failed with reason, recommend manual lookupSame company appears multiple times (multiple inbound leads):
Lead claims a title that doesn't match LinkedIn:
Company recently renamed, merged, or was acquired:
Person left the company since filling the form:
Enrichment tool rate limits or failures:
enrichment_partial and move onVery high volume (100+ leads):
Personal email domains:
company_unidentified, enrich person onlyAfter enrichment is complete, update the source systems:
inbound-lead-qualification flags leads as insufficient_datainbound-lead-triage detects leads with missing company/title fieldscompany_name — What company do they work for?Render a 'model comparison grid' video from a config — a fal-style "same prompt, N contenders" showcase — a dark real-DOM stage where per beat a monospace prompt fades in centered, docks to a small top strip, then a labeled 2-4 panel grid (static images OR muted video clips, mixable per cell) staggers in and holds for comparison, plus a minimal end card — frame-stepped via Playwright (video cells are frame-seeked deterministically) and encoded with FFmpeg. Deterministic assembly, FREE (cell media comes from create-image-fal / create-video-fal, music from create-music-elevenlabs), text stays pixel-crisp. Use for the model-comparison-grid format.
Render a punchy ~12s vertical (9:16) music-only direct-response OFFER ad as a 4-beat kinetic-typography film — HEADLINE slam → real PRODUCT drop → CLAIM/proof → CTA pill — from one config of copy slots, a real product photo, a brand palette, fonts, bpm, and beat split. DETERMINISTIC + FREE (a bundled Remotion project; springs + interpolate, no AI-gen for visuals). Backgrounds are engine gradient divs off the palette, props are inline SVG, the ONLY composited bitmap is the REAL product photo (objectFit:contain, never stretched), and ALL headline/claim/CTA/URL/wordmark text is typeset in the engine — never AI-rendered (the format's credibility guard). A driver binds the config to Remotion input props, renders the 9:16 master, and derives a 1:1 center-crop with ffmpeg. Two gating checks run before render (claim verbs must match the product's physical format; the claim beat needs an edge-entry mechanism prop). Use for the motion-graphics-offer-ad format.
Assemble a myth-vs-fact kinetic-typography explainer video ad (≈29.5s, 9:16) from N myth/fact pairs + hook / turn / punch copy + palette + a brand end-card PNG + a VO track — a hook, 3 red-strike MYTH cards that flip to teal-check FACT cards (per-line strikethrough that crosses EVERY wrapped line), a "what actually works" turn, an optional proof reveal, a punch line, and a static end card. DETERMINISTIC assembly with ZERO AI-gen visuals — HTML hyperframes rendered frame-exact via Playwright (`window.renderAt(t)`, animation a pure function of beat-local time), Whisper beat-snap to VO word onsets, concat at a uniform fps, karaoke `.ass` captions burned last (suppressed on the proof + end-card beats), and a VO + optional music mix (music −20 dB, `amix normalize=0`, tail fade). FREE (Python + Playwright + ffmpeg); the recipe supplies the copy / palette / end-card / VO and gates the paid VO / music / Whisper calls to their own capabilities. Use for the myth-vs-fact format.