mcpField
I
inbound-lead-qualifier-skill

inbound-lead-qualifier-skill

github.com/scientiacapitalMarketing & growth2836 installsUpdated 3w ago
Repository

About inbound-lead-qualifier-skill

A Claude skill that qualifies, scores, and routes inbound leads using HubSpot data and enrichment. It stages first-touch email as a Gmail draft and requires checks before customer-facing claims.

Key features

  1. 01HubSpot contact and company lookup
  2. 02Qualification gates and lead scoring
  3. 03Enrichment for qualified leads
  4. 04Tier-based routing with response SLAs
  5. 05Gmail draft and HubSpot follow-up proposal

Use cases

  1. 01Triage demo and pricing inquiries
  2. 02Prioritize leads by fit, intent, and urgency
  3. 03Route existing customers or partner inquiries
  4. 04Prepare a reviewed first-touch email

MCP support

Uses MCP tools for HubSpot lookup, qualification, enrichment, product search, copy review, and Gmail draft creation; customer-facing email is staged, never sent.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/scientiacapital/skills --skill inbound-lead-qualifier-skill

After installing, type/inbound-lead-qualifier-skillin Claude Code to confirm it loaded.

Bundled filesconfig.json

Details

From the project README

Inbound Lead Qualifier & Router

Turn an inbound signal into a decision in under two minutes: pull the contact from HubSpot, let `qualify_lead` decide whether it is a lead at all (customer, channel, product-only engager, AE-owned, suppressed) and what tier it carries, enrich what is missing, score ICP fit + intent + urgency to a 0-100 priority with a response SLA, route it (Tim works it, or demo booked and handed to an AE), and stage the first-touch email as a Gmail draft. Speed to lead: the whole run should finish inside the 60-minute speed-to-lead window CLAUDE.md sets. Keywords: `inbound lead`, `qualify inbound`, `score lead`, `demo request`, `form fill`, `triage`

<quick_start> Trigger: "qualify this inbound lead", "score and route [name] from [company]", "triage inbound". Input: name + company, or email, or a pasted form notification. Optional: source, form fields.

Tool order:

  1. hubspot_search_contacts → hubspot_get_contact (Epiphan AI) — the record, its conversions, page views, owner, lifecycle. hubspot_get_company for the account.
  2. qualify_lead (Epiphan AI) — Gate Q. Verdict decides exclude / STALE AE LEAD / tier before anything is scored.
  3. enrich_contact (Epiphan AI) — title, seniority, org size, LinkedIn for rows that passed Gate Q. Fallback: apollo_people_match (Apollo plugin).
  4. Score (Stage 4) → route (Stage 5).
  5. Gate S (search_product_catalog + Epiphan Knowledge search) on any product the form names; Gate B (get_writing_style once, check_my_copy per string) on the email and call opener.
  6. Deliver: Gmail create_draft from [email protected] (never send); HubSpot note + task, confirm-first; AE path → ae-handoff-brief-skill. </quick_start>

<house_rules> Customer-facing skill. Before output, run the gates in order (details: ~/.claude/skills/epiphan-house-rules-skill/reference/gates.md): S: search_product_catalog (Epiphan AI) or Epiphan Knowledge search before any product claim. B: check_my_copy on every customer-facing string. Q: qualify_lead right after the candidate pull, before tiering/enrichment/drafts. D: outbound text becomes a Gmail draft, never a send. Identifiers (owner IDs, portal, emails, seats) come from reference/identifiers.md in that skill — do not restate them here. On any gate failure follow reference/self-healing.md (retry, degrade with a flag, alert Tim, halt) and append a line to ~/.claude/skill-runs/.jsonl. </house_rules>

<success_criteria>

  • Contact resolved in HubSpot (or flagged not in HubSpot and scored from the pasted form)
  • qualify_lead verdict recorded: excluded-with-reason, STALE AE LEAD, or tier ATL/GRAY/BTL
  • Enrichment attempted only for leads that passed Gate Q
  • Score 0-100 with the three components shown and the inputs that produced them
  • Priority tier + SLA + route (Tim / AE via ae-handoff-brief / CSM / channel) with one-line reason
  • Qualification questions (must-ask + good-to-ask) tied to the vertical and the form's stated need
  • Product lines in the email/opener passed Gate S; every customer-facing string passed check_my_copy
  • First-touch email exists as a Gmail draft; HubSpot note/task proposed, not written silently
  • Outcome sidecar + run-log line written </success_criteria>

Stage 1: Resolve the Lead in HubSpot

MCP Tools: mcp__claude_ai_Epiphan_Ai__hubspot_search_contacts (by email, else name + company) → mcp__claude_ai_Epiphan_Ai__hubspot_get_contact → mcp__claude_ai_Epiphan_Ai__hubspot_get_company.

Pull: firstname, lastname, email, phone, jobtitle, company, country, lifecyclestage, hs_lead_status, hubspot_owner_id, first_conversion_event_name, recent_conversion_event_name, recent_conversion_date, hs_analytics_num_page_views, hs_analytics_last_url, notes_last_updated, device_count, is_channel, company industry, numberofemployees, domain.

  • Multiple matches → take the record with the most recent conversion; list the others as possible duplicates for Gate Q.
  • No match (lead arrived as a pasted form notification) → continue with the form data, mark not in HubSpot, and propose hubspot_create_contact at delivery (confirm-first).
  • Source precedence: the form/conversion name in HubSpot beats what the user typed.

Stage 2: Gate Q — qualify_lead decides whether this is a lead

MCP Tool: mcp__claude_ai_Epiphan_Ai__qualify_lead on the contact (and the company when the contact is new).

VerdictRoute (stop scoring)
Existing customer (device_count >= 1 / lifecycle customer)Expansion or support, not inbound: hand to the owning AE/CSM with a one-line note. No draft to the prospect.
Channel partnerChannel manager; no draft.
Product-only engager (setup / registration form, not demo or pricing)Support ticket, not a lead. Note it; stop.
AE-owned, activity < 90 daysNotify the owning AE (Slack/email note), no BDR draft.
AE-owned, stale > 90 daysSTALE AE LEAD — score it, present to Tim with the AE name; Tim decides whether to re-engage.
Suppressed (bdr_suppressed / local suppression file)Stop; say why. New inbound engagement is itself a release signal — flag for Tim rather than silently reviving.
PassContinue. Tier (ATL / GRAY / BTL / NEVER) comes from this verdict; taxonomy in CLAUDE.md, not restated here.

Non-NA leads: flag, still score, route to the regional owner per identifiers.md. qualify_lead unavailable after one retry → produce the score with [Gate Q unverified], no draft, no routing, outcome partial, alert Tim.

Stage 3: Enrich What Is Missing

MCP Tool: mcp__claude_ai_Epiphan_Ai__enrich_contact for title, seniority, department, LinkedIn, org size. Fallback mcp__plugin_sales_apollo__apollo_people_match. Skip if HubSpot already has title + company size. Enrichment failure is a partial, never a stop — score with what is known and mark the missing inputs.

Stage 4: Score

ICP Fit (0-40) — Epiphan verticals, not generic SaaS:

  • Vertical ICP (0-10): map the CLAUDE.md vertical score (Higher Ed 90, Courts/Legal 85, Government 80, Corporate AV 80, Healthcare 75, Houses of Worship 70, K-12 65) ÷ 9; unknown vertical = 4.
  • Buyer tier (0-10): ATL 10 · GRAY 6 · BTL 3 · NEVER 0 (from Gate Q).
  • Org fit (0-10): multi-room / multi-site / recurring capture need visible in form, company size, or site = 8-10; single-room hobby use = 2-4.
  • Budget signal (0-10): stated budget or quote request 10; active grant / fiscal-year language 7; prior deal history 6; none 3.

Intent (0-30): demo request 30 · pricing/quote 20 · content download or webinar 10 · general inquiry 5. Add +5 if hs_analytics_num_page_views > 5 in the last 30 days (cap 30).

Urgency (0-30): "ASAP" / dated event 30 · timeline stated 20 · "exploring" 10 · none 5.

TotalPrioritySLADefault route
80-100🔴 HOTcall within 1 hourATL/GRAY → book demo, hand to AE via ae-handoff-brief-skill; BTL → Tim calls, finds the EB
60-79🟡 WARMcall within 24 hoursTim works it; demo once EB and timeline confirmed
40-59🟢 COOLemail first, then callTim; Gmail draft + Nooks sequence proposal
< 40⚪ NURTUREno callmarketing nurture; note on contact

Stage 5: Route

  • AE path (HOT + ATL/GRAY, or any deal the form sizes above the BDR threshold): pick the AE by territory/book in reference/identifiers.md of the house-rules skill; do not write owner IDs here. Hand off with ae-handoff-brief-skill; owner change is confirm-first (hubspot_update_contact_owner).
  • Tim path (everything else that passed Gate Q): Tim is the BDR of record; set the call task.
  • Existing customer / channel / support: per the Stage 2 table. Give one line of "why this route" (tier, vertical, score, territory).

Stage 6: Gates S and B before any customer-facing text

  • S: for every product the form or the opener names: search_product_catalog (Epiphan AI) → Epiphan Knowledge search/fetch. Discontinued products get an EOL acknowledgement and a current-lineup pointer, never a spec. No live result → [spec unverified] and partial.
  • Competitor lines (Extron, Matrox, Blackmagic, Crestron, vMix, Teradek): verified the same way or left out — "probably comparing to X" is allowed only as an internal note to Tim, never in the draft.
  • B: get_writing_style once per session; check_my_copy on the email subject, body, and the call opener. Apply corrections before staging. Brand MCP down → stage with [brand check skipped].

Stage 7: Deliver

  1. Gmail draft — mcp__claude_ai_Gmail__create_draft, from [email protected], to the lead. Subject Re: <form/demo request> — <Company>. Body: one line acknowledging the specific form and what they asked for, one verified product line only if relevant, one calibrated question, a 15-minute ask. Never send_message.
  2. HubSpot — propose, then on confirmation: hubspot_create_contact_note ("Inbound scored /100 ; route ; reason …") and hubspot_create_contact_task for the call inside the SLA. not in HubSpot leads → hubspot_create_contact first (confirm-first).
  3. Chat output (the decision card):
# Inbound: <Name> — <Company>            Source: <form> · Received: <ts>
Score <n>/100  🔴/🟡/🟢/⚪  SLA: <x>   Gate Q: pass | STALE AE LEAD (<AE>) | excluded: <reason>
ICP <n>/40 (vertical <v> · tier <t> · org <o> · budget <b>) · Intent <n>/30 · Urgency <n>/30
Route: <Tim | AE <name> via ae-handoff-brief | CSM | channel>  — why: <one line>
Must-ask: 1. what is driving this now  2. current setup / what breaks  3. timeline + event
          4. who signs  Good-to-ask: success picture · budget range · alternatives seen
Call opener (brand-checked): "<2 sentences>"
Draft: <Gmail draft id>   HubSpot: note + task proposed (confirm)   Flags: [spec unverified] [brand check skipped] [not in HubSpot]
qualify this inbound lead: Maria Lopez, Director of Academic Technology, Riverside Community College, demo request form, "need lecture capture in 12 rooms by fall" HubSpot hit, qualify_lead pass, tier ATL. Score 93 (ICP 38: Higher Ed 10, ATL 10, 12 rooms 10, fiscal-year 8 · Intent 30 · Urgency 25). 🔴 HOT, 1-hour SLA, route AE via ae-handoff-brief (NA, Higher Ed). Pearl Nexus line verified via search_product_catalog + Epiphan Knowledge. Gmail draft staged, note + task proposed. score and route Dan Wu from Acme Studios, pricing page form qualify_lead: existing customer (device_count 2). Not scored as inbound; routed to owning AE as expansion with a one-line note. No prospect draft.

<anti_patterns>

  • Scoring from the pasted text alone when the contact exists in HubSpot.
  • Writing a call script with product or competitor claims that never passed Gate S.
  • Hardcoding AE names/owner IDs in this file — identifiers.md owns them.
  • Sending the first-touch email instead of drafting it.
  • Re-implementing the suppression check inline; qualify_lead already applies it. </anti_patterns>

<self_healing> success = resolved, gated, scored, routed, draft staged. partial = decision card produced but a stage degraded (enrichment failed, Gate S/B skipped and flagged, HubSpot note not confirmed, Gate Q unverified → no draft). error = lead could not be identified at all (no name/company/email usable). Ladder per ~/.claude/skills/epiphan-house-rules-skill/reference/self-healing.md: retry once → degrade with a flag → alert Tim → halt. Append one line per run to ~/.claude/skill-runs/inbound-lead-qualifier-skill.jsonl. </self_healing>

Emit Outcome Sidecar

As the final step, write to ~/.claude/skill-analytics/last-outcome-inbound-lead-qualifier-skill.json:

{"ts":"[UTC ISO8601]","skill":"inbound-lead-qualifier-skill","version":"<frontmatter version>","variant":"default",
 "status":"[success|partial|error]","runtime_ms":[estimated ms from start],
 "metrics":{"leads_qualified":[n],"hot_leads":[n],"warm_leads":[n],"cool_leads":[n],"nurture":[n],"excluded_by_qualify":[n],"stale_ae_surfaced":[n],"routed_to_ae":[n],"drafts_created":[n],"avg_score":[n]},
 "error":null,"session_id":"[YYYY-MM-DD]"}

Use status "partial" if some stages failed but results were produced; error must name the stage. Use "error" only if no output was generated.

Comments

Markdown supported