Score and qualify sales leads with a small model people can trust: separate fit and intent scores, hard gates for true disqualifiers, decay so stale activity stops routing, thresholds set from outcomes, and a monthly review that compares bands against what actually closed. Use when someone asks to build, fix, audit, or explain a lead scoring model, set MQL thresholds, prioritize a lead list, or stop reps complaining about lead quality. For researching one named account use account_planning; for diagnosing where a pipeline leaks use sales_pipeline_leak_diagnosis.
./install.sh lead-scoringname: "lead_scoring" description: "Score and qualify sales leads with a small model people can trust: separate fit and intent scores, hard gates for true disqualifiers, decay so stale activity stops routing, thresholds set from outcomes, and a monthly review that compares bands against what actually closed. Use when someone asks to build, fix, audit, or explain a lead scoring model, set MQL thresholds, prioritize a lead list, or stop reps complaining about lead quality. For researching one named account use account_planning; for diagnosing where a pipeline leaks use sales_pipeline_leak_diagnosis."
Lead scoring ranks leads so reps work the ones most likely to buy first, and so marketing can prove which of its leads were worth sales time. A model does that job only if it stays small, separates two different questions, and gets checked against real outcomes on a schedule.
The two questions, kept separate in every serious implementation: fit (who is this lead, how closely do they match the customers you win) and intent, also called engagement or behavior (what have they done recently that shows interest). Salesforce Account Engagement makes the same split, a score from implicit buying signals and a grade from explicit profile factors. HubSpot supports separate fit, engagement, and combined scores for the same reason. One blended number hides the difference between a perfect-fit lead who has gone quiet and a poor-fit lead clicking everything, and those two leads need opposite handling.
This skill ships three things: the method below, a working scorer at bin/score.py, and an outcome-review loop in references/outcome-review.md. It does not ship universal point values. No honest set exists. Point values are a local decision that your outcome data revises.
List the traits your closed-won customers share and your disqualified leads share: industry, company size, region, role and seniority of the contact, segment, required technology or budget signals where you actually know them. Use won and lost records, not the ideal customer slide. Pick four to six fit factors. More than that and you are scoring data you do not reliably have. Mark the facts that end the conversation outright (competitor, region you do not serve, segment you do not sell to) as gates, not as big negative numbers a busy lead can out-click.
List the actions a lead can take, ordered by what each one costs the lead: a demo or contact request at the top, then pricing page visits, trial or product use, event attendance, content downloads, email clicks at the bottom. Email opens sit below clicks or out of the model entirely, since privacy features in mail clients make opens unreliable. Give the top action roughly double the next tier, the next tier roughly double the one below. Every intent factor carries a time window (in the last 30 days, say) and the score decays when activity stops: after a grace period, intent loses points for each quiet month, down to zero. Fit does not decay. A company does not stop matching your profile because it went quiet; its interest level is what went stale.
Put gates, factors, thresholds, and decay in one JSON model file following references/model-file.md, then run the scorer on a real export:
bash
python3 ~/workspace/skills/lead-scoring/bin/score.py score \
--model references/model-example.json \
--leads references/leads-example.csv --out scored.csv
Read the output by hand before you trust it. Check the top ten ROUTE leads: would a rep thank you for each one? Check the DISQUALIFIED list for anyone a gate caught wrongly. Check a good-fit lead with old activity: decay should have moved it to NURTURE. The worked example in references/model-file.md walks through eight leads covering all four bands.
A lead routes to sales when fit AND intent both clear their bars. Set the bars from step 5's backtest when you have history; without history, start where only a lead with real fit plus one strong intent action (or several weak ones) can route, and expect to move the bars at the first review. Write down the action and the response time for each band before launch: ROUTE gets a rep and a same-day first touch, NURTURE gets marketing nurture and re-scoring on new activity, HOLD gets enrichment or nothing, and DISQUALIFIED gets a recorded reason and no outreach. A band with no action attached is decoration. Sales confirms qualification facts on the call (budget, authority, need, timing); the score earns the call, it does not replace it.
Score last quarter's leads using the data as it stood when they arrived, then compare bands against what actually happened: meetings, opportunities, wins. Conversion should fall band by band. If a lower band converts like the band above it, the model is not separating anything and launching it will teach reps to ignore scores within a month. Fix the weights or the bars and backtest again. Follow references/outcome-review.md.
Monthly for the first quarter, then quarterly, and right after any change to the offer, pricing, segment, or sales motion. Each review: export band at handoff plus final outcome, run the review mode, check per-signal lift, make at most one change, and write down what changed and why.
bash
python3 ~/workspace/skills/lead-scoring/bin/score.py review --scored export.csv
The full procedure, including the feedback-loop trap (reps work high scores first, so high scores convert partly because of the attention), is in references/outcome-review.md.
One named owner for the model file, changes in version control, and the whole model printable on one page. When a rep asks why a lead scored what it scored, the scorer's reason column must answer it factor by factor. A model no one can explain gets worked around, and a worked-around model is worse than none because its reports still look authoritative.
One scoring package, containing:
bin/score.py, spot-checked by hand.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.