Agent skill
lead-scorer
Score raw leads as HOT/WARM/COOL based on config-driven weights from agency.config.json
Filed under Prospecting and list building.
From ekatasingh1107/b2b-gtm-skills · 99 skills · 2 · pushed 2026-04-11
What it does when it runs
Score raw leads as HOT/WARM/COOL based on config-driven weights from agency.config.json
Read from the skill and the 2 files bundled beside it. A skill’s own description is written to be selected by an agent, so it describes the job and not the dependencies.
- Keys and connectors you must supply
- None found.
- Hosts it reaches
- No third-party host appears in the skill or its bundled files.
- Tool permissions it declares
- No
allowed-toolsin the frontmatter. It only issues instructions, so there is nothing to bound. - Actions present in the files
- None. Instructions only.
Install it
View source on GitHub ↗git clone --depth 1 --filter=blob:none --sparse https://github.com/ekatasingh1107/b2b-gtm-skills.git /tmp/b2b-gtm-skills git -C /tmp/b2b-gtm-skills sparse-checkout set "skills/capabilities/lead-scorer" mkdir -p ~/.claude/skills/lead-scorer cp -R "/tmp/b2b-gtm-skills/skills/capabilities/lead-scorer/." ~/.claude/skills/lead-scorer/
Picked up without a restart. A project skill of the same name is shadowed by your personal one. For one repository only, swap ~/.claude/skills for .claude/skills. Claude Code docs ↗
The folder is the same in every client that implements the format — 46 of them — so if yours is not above, only the destination changes.
The skill
Source on GitHub ↗Reproduced in full from ekatasingh1107/b2b-gtm-skills/blob/eae8dd0bb98da1c8e84abd297066a87015dd860f/skills/capabilities/lead-scorer/SKILL.md, which is licensed MIT (repository). 1,145 words, 19 headings.
Lead Scorer
Scores inbound or scraped leads using a multi-factor algorithm. All weights, thresholds, and bonuses are read from agency.config.json so the scoring adapts to any agency without code changes.
Prerequisites
agency.config.jsonexists at the repo root with ascoringsection containing:platform_weights,hiring_signals,budget_tiers,recency_bonuses,market_boosts,thresholdsicpsection withprimary_keywords,secondary_keywords,intent_keywords,negative_keywords- Lead data in structured format (JSON object or array)
Phase 0: Intake
- Read
agency.config.jsonfrom the project root. - Extract:
scoring.platform_weights-- map of platform name to base scorescoring.hiring_signals-- array of phrases that indicate active hiring/buyingscoring.budget_tiers-- array of{min, points}sorted descending byminscoring.recency_bonuses-- map of time window to bonus points (e.g.,"24h": 15)scoring.market_boosts-- map of market/country to bonus pointsscoring.contact_surface_bonus-- bonus points for multi-channel reachabilityscoring.thresholds--{hot, warm}cutoffsicp.primary_keywords-- high-relevance service keywords (+10 each match)icp.secondary_keywords-- medium-relevance keywords (+5 each match)icp.intent_keywords-- buying-intent phrases (+10 each match)icp.negative_keywords-- disqualifiers (score = 0, immediately reject)outreach.daily_targets-- { company_leads: 5, gig_leads: 20, total: 25 }outreach.geo_split-- { international_pct: 75, india_pct: 25 }
- Accept the lead(s) to score. Each lead should have as many of these fields as available:
title-- the post/gig/job title or subject linedescription-- the full text bodyplatform-- where the lead was foundbudget-- numeric budget amount (if available)currency-- budget currencyposted_at-- ISO timestamp or relative time stringcountry-- country of the lead or companyurl-- source URLlead_type-- "gig" or "company" (from signal-scanner classification)geo_bucket-- "international" or "india" (from signal-scanner)
Phase 1: Negative Keyword Check
For each lead, scan title and description against every entry in icp.negative_keywords (case-insensitive substring match).
- If ANY negative keyword matches: score = 0, tier =
REJECTED, skip all remaining phases for this lead.
Phase 1.5: Lead Type Awareness
Apply different scoring standards based on lead_type:
Company Leads (target: 5/day)
- Apply FULL scoring algorithm (all phases below)
- Extremely high quality bar: only HOT leads pass
- Company leads must score >= thresholds.hot to be included
Gig Leads (target: 20/day)
- Apply simplified scoring: platform base + keyword match + budget + recency
- Skip hiring signal bonus (gigs ARE the hiring signal)
- Higher volume: HOT threshold is sufficient
- Must have clear buying signal and budget to qualify
Phase 2: Platform Base Score
Look up lead.platform in scoring.platform_weights.
- If the platform exists in the map:
base_score = platform_weights[platform] - If the platform is not in the map:
base_score = 10(default floor)
Phase 3: Keyword Match Scoring
Combine title + description into a single lowercase text blob. For each keyword list, count distinct keyword matches (not occurrences):
- Primary keywords: For each match, add +10 points. Cap at 3 matches (max +30).
- Secondary keywords: For each match, add +5 points. Cap at 3 matches (max +15).
- Intent keywords: For each match, add +10 points. Cap at 2 matches (max +20).
keyword_score = primary_points + secondary_points + intent_points
Phase 4: Hiring Signal Bonus
Scan the text blob against scoring.hiring_signals (case-insensitive).
- If ANY hiring signal matches: add +20 points (one-time bonus, not per-match).
- Note: For gig leads (
lead_type == "gig"), skip this phase. Gigs ARE the hiring signal, so the bonus is already baked into the platform base score.
Phase 5: Budget Tier Scoring
If lead.budget is a number > 0:
- Iterate
scoring.budget_tiersfrom highestminto lowest. - The first tier where
lead.budget >= tier.mingivesbudget_points = tier.points. - If no budget data:
budget_points = 0.
Phase 6: Recency Bonus
Calculate the age of the lead from lead.posted_at relative to now.
- If age <= 24 hours: add
scoring.recency_bonuses["24h"]points - Else if age <= 48 hours: add
scoring.recency_bonuses["48h"]points - Else if age <= 72 hours: add
scoring.recency_bonuses["72h"]points - Else: 0 points
If posted_at is not available: 0 points.
Phase 7: Market Boost
Look up lead.country in scoring.market_boosts (case-insensitive, also check common abbreviations like "US" for "United States").
- If found: add the boost points.
- If not found: 0 points.
Phase 7.5: Contact Surface Bonus
If the lead includes a contact_surfaces object:
channel_count >= 3: addscoring.contact_surface_bonus.channels_3_pluspoints (default 15)channel_count == 2: addscoring.contact_surface_bonus.channels_2points (default 5)channel_count <= 1or missing: 0 points
This bonus rewards leads reachable through multiple channels, enabling the full multi-channel outreach cadence.
Phase 8: Final Score and Tier Assignment
total_score = base_score + keyword_score + hiring_bonus + budget_points + recency_bonus + market_boost + surface_bonus
Assign tier using scoring.thresholds:
total_score >= thresholds.hot=> HOTtotal_score >= thresholds.warm=> WARMtotal_score < thresholds.warm=> COOL
Phase 8.5: Geo Split Enforcement
After scoring all leads, enforce the 75/25 geo split from config:
- Separate scored leads into two pools: international and india
- Target: ~75% international (~19 of 25 leads), ~25% India (~6 of 25 leads)
- Within each pool, rank by score descending
- Select top N from each pool to hit the target split
- If one pool is short, allow the other pool to fill remaining slots
For company leads specifically (5/day target):
- ~4 international, ~1 India
For gig leads (20/day target):
- ~15 international, ~5 India
Flag any lead that was excluded due to geo split enforcement:
"excluded_reason": "geo_split_cap_reached"
Phase 9: Output
Return a JSON array of scored leads:
[
{
"url": "https://...",
"platform": "Freelancer",
"title": "Need Shopify developer for store redesign",
"score": 75,
"tier": "HOT",
"lead_type": "gig",
"geo_bucket": "international",
"breakdown": {
"platform_base": 45,
"keyword_matches": {
"primary": ["shopify developer", "shopify redesign"],
"secondary": ["ecommerce redesign"],
"intent": ["need a developer"]
},
"keyword_score": 30,
"hiring_signal": true,
"hiring_bonus": 20,
"budget_points": 0,
"recency_bonus": 0,
"market_boost": 0,
"surface_bonus": 15,
"channel_count": 4
},
"reject_reason": null
}
]
For rejected leads, include "reject_reason": "Matched negative keyword: 'i am a shopify developer'" and "tier": "REJECTED".
Phase 10: Log
If the CRM is configured, write scored leads to the CRM using the crm-writer skill. Log: url, platform, title, score, tier, lead_type, geo_bucket, scored_at timestamp.
Summary format:
Scored {N} leads:
- HOT: {count}, WARM: {count}, COOL: {count}, REJECTED: {count}
Geo split: X% international, Y% India (target: 75/25)
Lead mix: N company leads, N gig leads (target: 5/20)
Example Usage
Trigger phrases:
- "Score these leads"
- "Qualify this lead list"
- "Run lead scoring on these results"
- "Which of these leads are hot?"
User: Score these leads from today's signal scan
Assistant: [reads agency.config.json, applies scoring algorithm with lead type awareness and geo split enforcement, returns sorted JSON with HOT leads first]
Files bundled with it
These load only when the skill asks for them, so they cost nothing until it runs.
Other skills for the same job
Different authors, same problem. Matched on the words in the skill name, across every library in the catalogue except this one.
- no-lead-left-behind-lead-treatment-audit by zapier · 334
- lead-magnets by coreyhaines31 · 46,928
- lead-dossier by ericosiu · 3,483
- lead-magnet by OpenClaudia · 677
- lead-magnet-brainstorm by growthenginenowoslawski · 668
- daily-lead-steward by zapier · 334
- find-lead-account-owner by zapier · 334
- inbound-lead-audit-cx-map by zapier · 334
Need help setting it up?
This page tells you what lead-scorer does and what it needs. Cheetah builds the agent setup it runs inside: data, CRM, sequencing and the guardrails.
Book a call →The directory stays free. There is nothing gated behind this.