Skill

Lead Triage Router

Scores inbound leads with a tunable ICP-fit and intent rubric, assigns a tier and a routing owner from your territory rules, and prints the exact signals behind every score so reps can see why a lead reached them.

At a glance

Lead Triage Router is an AI skill that you can use in Claude Code, Codex, or type.com.

Updated

See an example

Example output from a sample run. Company names and figures are sample data.

Lead triage and routing: 19 inbound leads, as of 2026-09-22

5 Tier A leads are sales-ready now, led by Derek Nwosu at Kestrel Payments (94.0), routed to Alex Rivera on a 2h SLA. The rest split into 3 Tier B, 7 Tier C, 1 Tier D and 3 disqualified, including a 69.2 founder lead below the 10-employee floor.

Tier A and B leads

TierScoreLeadFitIntentRoute (SLA)
A94.0Derek Nwosu, Kestrel Payments90.0100.0enterprise-na / Alex Rivera (2h)
A86.0Priya Shah, Northwind Logistics90.080.0enterprise-na / Alex Rivera (2h)
A83.8Paulo Mendes, Vertex Freight89.076.0enterprise-apac / Wei Chen (4h)
A83.2Ken Arai, Meridian Manufacturing88.076.0enterprise-apac / Wei Chen (4h)
A72.7Marcus Feld, Atlas Bio Labs86.052.7enterprise-emea / Ingrid Solberg (4h)
B67.8Amara Osei, Cascade Fintech81.048.0sdr-outbound / SDR pod 1 (12h)
B57.6Mira Lindqvist, Lantern Bay Hotels52.066.0sdr-outbound / SDR pod 1 (12h)
B52.8Robert Kline, Silverline Energy88.00.0enterprise-na / Alex Rivera (8h)

…plus 7 Tier C, 1 Tier D and 3 disqualified leads in the full report. Scoring: total = 0.60 x fit + 0.40 x (intent x recency); intent shown after recency.

Why Marcus Feld scored 72.7: fit 86.0 from 3,200 employees +30, revenue $900,000,000 +20, Healthcare +14, Germany +8 and a director title +14. Intent 62.0 from a started trial +30, pricing page views +8, 2 content downloads +8, 4 sessions +8 and a webinar +8, discounted x0.85 because his last activity was 21d ago, giving 52.7.

Routing load

QueueOwnerLeads
sdr-sequenceSDR pod 27
marketing-nurture(none)4
enterprise-naAlex Rivera3
enterprise-apacWei Chen2
sdr-outboundSDR pod 12
enterprise-emeaIngrid Solberg1

Next actions

  • Work Tier A immediately; qualify Tier B before routing to an AE; sequence Tier C, do not call; Tier D is marketing nurture only.
  • Robert Kline (Silverline Energy, referral) has fit 88.0 but no activity date on record, so intent scored 0.0.
  • Disqualified to marketing-nurture: Sana Iqbal, Tiny Tools Co (4 employees is below the 10 floor); Bill Hartley, Peak Staff Group (blocked industry: Staffing); Jen Larkin, Solstice Apparel Supply (personal email domain gmail.com).
  • Hana Kovacs (Brightwater Utilities) is missing employee_count and annual_revenue_usd; missing fields score zero rather than guessing.

Inputs: an inbound lead export, territory routing rules and the scoring rubric in config/rubric.json.

Produced by running bash examples/run.sh on the sample data bundled with this skill.

How to use Lead Triage Router

  1. type.com: Choose Use Skill to add Lead Triage Router to your type.com workspace.
  2. Claude Code: Download the skill and extract it into ~/.claude/skills/lead-triage-router/ (or .claude/skills/lead-triage-router/ in a project). Then ask Claude to use Lead Triage Router.
  3. Codex: Download the skill and extract it into ~/.agents/skills/lead-triage-router/ (or .agents/skills/lead-triage-router/ in a repository). Then ask Codex to use Lead Triage Router.

AI agents can read this page as Markdown or fetch the raw SKILL.md.

Frequently asked questions

What is Lead Triage Router?

Lead Triage Router is an AI skill that you can use in Claude Code, Codex, or type.com.

What does Lead Triage Router do?

Scores inbound leads with a tunable ICP-fit and intent rubric, assigns a tier and a routing owner from your territory rules, and prints the exact signals behind every score so reps can see why a lead reached them.

Can I use Lead Triage Router in Claude Code or Codex?

Yes. Lead Triage Router is a standard Agent Skills folder with a SKILL.md file. Download it and extract it into ~/.claude/skills/ for Claude Code or ~/.agents/skills/ for Codex.

Who created Lead Triage Router?

The type.com team created Lead Triage Router. The type.com team reviews every skill before it is published in the Skills Library.

AI for SDRs: a practical guide

Browse the technical files
---
name: lead-triage-router
description: Scores inbound leads with a tunable ICP-fit and intent rubric, assigns a tier and a routing owner from your territory rules, and prints the exact signals behind every score so reps can see why a lead reached them.
---

# Lead Triage and Router

Takes a raw inbound lead export and produces a tiered, routed, explainable
work list. The rubric lives in `config/rubric.json`, not in the code, so
marketing and sales can argue about weights in a pull request instead of in a
meeting.

## Before you run

This skill ships scripts and sample data alongside this SKILL.md. Before running any command:

1. **Get the files.** Make sure the skill's other files (`scripts/`, `examples/` and anything else listed with this skill) are in your working folder at the same relative paths. Some environments load only SKILL.md; if yours did, fetch each file from this skill's published files and write it to the matching path. In Type, read them with the skill-file tools. Anywhere else, the Type Skills Library API lists every file with its path, content and `sha256`: GET `https://api.type.com/api/public/library/skills` and take the entry with slug `lead-triage-router`.
2. **Check the copies are exact.** Compare each file's size in bytes, not characters (and its hash, where your tools report one), with the published version before running. A copy written out from the published file is fine once its byte size and hash match; never run a script you summarised or reconstructed from memory.
3. **Run from the skill's folder**, calling interpreters explicitly: `python3 scripts/…` and `bash examples/run.sh`.
4. **Try the sample first.** If the skill ships `examples/run.sh` and `examples/expected_output.txt`, run `bash examples/run.sh`; its output should match the expected file exactly. If it doesn't, stop and report the first differing line rather than running on real data.

## When to use this

- Daily or hourly triage of form fills, trials, and content downloads when the
  volume has outgrown a human reading each one.
- Rebuilding lead scoring after an ICP change, a new segment, or a territory
  reshuffle — run the new rubric against last month's leads and compare.
- Auditing an existing scoring model: this shows its reasoning, whereas most
  CRM scoring does not.

## Inputs

`DATA_CONTRACT.md` has the exact columns, types, and units. You need:

1. `leads.csv` — one row per lead, firmographics plus intent counters.
2. `routing.csv` — the territory/queue rules, in priority order.
3. `config/rubric.json` — weights, bands, tiers, disqualifiers (ships with
   sensible B2B SaaS defaults).

### Gathering the inputs through Type integrations

- **HubSpot**: export contacts with `email`, `jobtitle`, `company`,
  `num_employees` (or the enriched company property), `annualrevenue`,
  `industry`, `country`, `hs_analytics_source`, `createdate`, and
  `notes_last_contacted`. Page-view and session counters come from the HubSpot
  analytics properties or from your product analytics tool.
- **Salesforce**: `Lead` object plus any enrichment fields (Clearbit, ZoomInfo,
  Apollo) that populate employee count, revenue, and industry.
- **Attio**: the People object joined to the linked Company record.
- **Product analytics (Amplitude, PostHog, GA4, warehouse)**: pricing page
  views, sessions, trial starts. Aggregate to a 30-day window ending on the
  date you pass to `--as-of` so the counters and the recency multiplier agree.
- **Routing rules**: usually a spreadsheet RevOps already maintains. If not,
  write it once by hand from the contract; it changes rarely.

If an enrichment field is missing, leave it blank. Blank fields score zero and
are listed in the data-quality section — do not guess values, because a guessed
employee count silently inflates a tier.

## Running it

```bash
python3 scripts/lead_triage.py \
  --leads path/to/leads.csv \
  --routing path/to/routing.csv \
  --config config/rubric.json \
  --as-of 2026-09-22
```

- `--as-of` is required and drives the intent recency multiplier.
- `--fallback-queue NAME` sets where leads go when no routing rule matches
  (default `unrouted`); those leads are counted separately in the summary.
- `--json` emits the full scored record, contribution by contribution.
- Bad input exits `2` naming the file, row, and column.

See `examples/run.sh` for a complete working invocation.

## How the score works

```
total = fit_weight x fit_score + intent_weight x (intent_score x recency_multiplier)
```

- **Fit (0-100)** sums five firmographic bands — employee count, revenue,
  industry, country, and title seniority — then normalizes against
  `fit.max_points`. Title matching is whole-word, so "Director" does not match
  the executive keyword list, and a multi-word keyword such as "head of" must
  match consecutive whole words, so "Forehead Office Manager" scores as a
  manager, not a head of function. An industry that is listed but scores below
  the `_default` is labelled as low-fit, not as an ICP industry.
- **Intent (0-100)** sums weighted behavioural signals. Count signals have a
  per-signal cap (three pricing-page views should not outscore a demo request),
  and the total is capped at `intent.max_points`.
- **Recency multiplier** discounts intent by how long ago the lead last did
  anything. A lead with no activity date is discounted to the floor rather than
  treated as fresh.
- **Disqualifiers** run before tiering. A personal email domain, a blocked
  industry or country, or a company below the employee floor sends the lead to
  the nurture queue with the reason attached, whatever it scored.
- **Tier** is the highest band whose `min_score` the total meets.
- **Routing** walks the rules in `priority` then `rule_id` order and takes the
  first match on tier, segment, and region. `*` is a wildcard; keep one
  catch-all rule at the bottom.

## Tuning

Edit `config/rubric.json`:

- `fit_weight` / `intent_weight` must sum to 1.0. Product-led motions usually
  run 0.4 / 0.6; enterprise outbound-heavy motions run 0.7 / 0.3.
- `fit.*_bands`, `industry_points`, `country_points`, `title_bands` — the ICP
  itself. Points are arbitrary units; only their ratio matters.
- `intent.signals` — add a field here and the contract, and it is scored. Caps
  stop one loud signal from dominating.
- `tiers[].min_score` — move these first when the A tier is too big for the
  team to work inside the SLA.
- `disqualifiers` — the hard filters, kept separate from scoring on purpose.

After any change, rerun against a week of known leads and check the tier counts
against what the team can actually handle.

## Reading and presenting the output

- **Summary** gives the tier distribution and average score. If Tier A is more
  than about 15% of volume, thresholds are too loose.
- **Routing load** is the operational number: how many leads each queue and rep
  just received. Check it against capacity before you send the assignments.
- **Per-lead blocks** are the deliverable. The `fit` and `intent` lines
  reconstruct the score exactly — paste them into the CRM note or the Slack
  handoff so the rep never has to ask "why did I get this?"
- **Data quality** tells you what enrichment is missing. Persistent blanks
  there are a better investment than another weight change.

## Limits

- It scores the *record*, not the person's real buying intent. A rubric cannot
  see a stalled budget cycle or a competitor already in the account.
- Keyword title matching is coarse. Unusual or non-English titles land in the
  default band; add keywords rather than accepting the drift.
- Counts are taken as given. If the 30-day window in the export does not end on
  `--as-of`, the recency multiplier and the counters disagree and scores skew.
- No deduplication: two form fills from the same person are two leads. Dedupe
  in the export, or in the CRM, first.
- No write-back. It does not assign owners in the CRM, send notifications, or
  enroll anyone in a sequence.
- Disqualifiers are rules, not judgment. A 4-person company with a real budget
  still gets filtered; review the DQ list weekly rather than trusting it blindly.