$npx -y skills add LaGrowthMachine/gtm-system --skill audience-icp-filterFilter an existing audience or lead list against your ICP and split it into ready-to-sequence segments. Use when someone already has a list of people — an audience in their sales tool, a CSV or CRM export, event or webinar attendees, registrants, a Sales Navigator import, a newsl
| 1 | # Audience ICP Filter |
| 2 | |
| 3 | Takes an audience that already exists and splits it into **ICP match**, **needs review** and **no match** — with the user's own team and competitors stripped out, and a reason attached to every decision. |
| 4 | |
| 5 | ## Authority — read this first |
| 6 | |
| 7 | - **Inlined below:** the coverage gate, the ICP question set, the seniority and function tiers, the exclusion doctrine, the two-pass rule, the naming convention, the anti-patterns, and the **fixed result UI**. This covers the common ~90% of lists. Work from these tables. |
| 8 | - **In `references/title-taxonomy.json`:** the full regex patterns behind seniority/function detection. **You do not need to read it** — `scripts/build.py` loads it. Consult it only if a user disputes a classification or wants to extend the taxonomy. |
| 9 | - **Never classify a list by hand.** Run the script, then run your own review pass over its output. Both passes are mandatory. |
| 10 | |
| 11 | ## Scope |
| 12 | |
| 13 | This skill starts from a list that **already exists**: an audience in the user's sales tool, or a CSV. It does not import or scrape — importing is a separate job with its own timing and prerequisites, and folding it in here would make the skill slower and less reliable for no gain. |
| 14 | |
| 15 | If the user hasn't imported yet, tell them to do that first, then come back with the audience. |
| 16 | |
| 17 | ## What it does |
| 18 | |
| 19 | Any audience is mostly noise: the user's own colleagues are in it, competitors are watching, and a third of the job titles are unreadable. This skill checks whether the data can support the ICP the user wants, asks what that ICP actually is, sorts the list, and writes the segments back as complementary audiences. |
| 20 | |
| 21 | ## Workflow |
| 22 | |
| 23 | **Step 0 — Load the list.** |
| 24 | From an LGM audience (`list_audiences` → `get_audience_leads`, paginating at 100/page until you have `total`), or from a CSV. Normalise to one object per person: `leadId` (or `firstname`+`lastname`), `jobTitle`, `companyName`, `proEmail`, plus `shortBio`, `location`, `industry` when present. |
| 25 | |
| 26 | **Step 1 — Coverage gate. Run this before asking about the ICP.** |
| 27 | ```bash |
| 28 | python3 scripts/build.py --coverage leads.json |
| 29 | ``` |
| 30 | It reports fill rates and names which criteria the data cannot support. There is no point offering geography filtering on an audience where `location` is empty — that just routes everyone to `review` and calls it a result. See *The coverage gate* below. |
| 31 | |
| 32 | **Step 2 — ICP Q&A**, informed by step 1. Don't offer criteria the data can't support without saying enrichment is needed first. |
| 33 | |
| 34 | **Step 3 — Pass 1, deterministic:** |
| 35 | ```bash |
| 36 | python3 scripts/build.py spec.json > pass1.json |
| 37 | ``` |
| 38 | It refuses invalid input rather than emitting a best-effort sort. If it errors, fix the spec — never work around it by classifying manually. |
| 39 | |
| 40 | **Step 4 — Pass 2, semantic. Mandatory.** Read every bucket, `match` first. Write overrides with reasons: |
| 41 | ```bash |
| 42 | python3 scripts/build.py --adjudicate review.json |
| 43 | ``` |
| 44 | |
| 45 | **Step 5 — Present** counts, segments, and what pass 2 changed. |
| 46 | |
| 47 | **Step 6 — Write complementary audiences** back (see below), or export a CSV. |
| 48 | |
| 49 | ## The coverage gate |
| 50 | |
| 51 | Field fill rates decide what is honestly filterable. Thresholds the script applies: |
| 52 | |
| 53 | | Field | Needed for | Below threshold means | |
| 54 | |---|---|---| |
| 55 | | `jobTitle` | Seniority + function detection | Classification is degraded — most leads land in `review` | |
| 56 | | `companyName` | Company-based exclusion | Exclusion is unreliable | |
| 57 | | `shortBio` | Catching people whose company **and** email are empty | Own-team and competitor exclusion **will leak** | |
| 58 | | `proEmail` | Domain-based exclusion | Job-changers slip through | |
| 59 | | `location` | Geography filtering | Geo criteria **cannot** be applied | |
| 60 | | `industry` | Industry filtering | Industry criteria **cannot** be applied | |
| 61 | |
| 62 | When the gate flags gaps, offer **profile enrichment — 1 credit per lead**. Quote the exact total (the script returns it) and get explicit approval |