Every revenue team I've worked with has an ICP document. It lives in Notion or a Google Doc or if someone was ambitious, a Confluence page that's three versions out of date. It says something like:
"Mid-market B2B SaaS companies, 50 to 500 employees, growing GTM teams, VP of Sales or CRO as champion."
And then it sits there. Completely useless to any system that might try to act on it.
The problem isn't that the description is wrong. It's usually directionally accurate. The problem is that a description is not a rule. A CRM doesn't know what "growing GTM teams" means. An enrichment workflow can't evaluate "mid-market." A scoring model can't run a qualifier check on "VP of Sales as champion" unless you've told it exactly where to look and what to look for.
This post is about the gap between those two things, the slide ICP and the rule ICP and what it actually takes to cross it.
Why the Gap Exists
The ICP slide was written to communicate, not to execute. It was built to align a team, onboard a new hire, and answer the question "who do we sell to" in a meeting. For those purposes, natural language is fine. Flexible, even.
But when you try to connect that ICP to anything that needs to run, a scoring model, a signal monitor, an outreach trigger, a rep's daily priority queue, natural language fails completely. "Mid-market" is ambiguous. "Growing GTM teams" requires interpretation. "We know a good fit when we see one" is what a founder says when they haven't extracted the pattern yet.
What's sitting behind that sentence is a real pattern. It exists. The founder built it from dozens of won and lost deals. The senior rep carries it intuitively. The problem is that it lives in people, not in the system and a system can only act on what it can evaluate.
Making the system useful means extracting the pattern and encoding it in something a machine can evaluate: a schema with fields, conditions, lookback windows, and explicit branching logic.
Starting with the Actual Pattern
Take the "I can just tell when a company is about to need us" instinct. That's not vague, it just hasn't been written down yet.
Ask the founder or the senior rep what they actually look for. Push on specifics. "What does a good account look like the week before you call them?" In my experience, you get something like:
"They're hiring SDRs. That means they're scaling outbound. And if they just hired a new VP of Sales, that person is going to make tooling decisions in the first 60 to 90 days. If they don't have a RevOps function yet, there's no one internally to build the system, that's where we fit. If they already have a VP of RevOps, they're probably building it themselves and we'd be a harder sell."
That paragraph contains four checkable conditions:
- VP of Sales hired in the last 90 days (lookback window + role)
- Actively hiring SDR or BDR roles (job posting signal + role type)
- No existing outbound infrastructure (negative qualifier)
- No RevOps leader present (disqualifier)
That's an ICP rule. It's what was always underneath the slide. The work is just extracting it and writing it in a form something else can read.
A Schema That Can Actually Run
Here's how I'd encode that pattern in YAML. This is illustrative, the specific fields map to whatever enrichment and signal sources you're pulling from (LinkedIn, Crunchbase, job board monitors, website analytics, whatever's in your stack).
icp_rule:
name: "vp-sales-new-hire-expansion"
version: "1.3.0"
description: >
Accounts building their first structured outbound motion under new sales leadership.
Strong fit when no RevOps function exists yet, internal build capacity is low.
qualifiers:
- field: "employee_count"
operator: between
values: [50, 500]
source: linkedin_headcount
- field: "industry"
operator: in
values: ["SaaS", "B2B Tech", "FinTech"]
source: crunchbase_category
- field: "tech_stack"
operator: contains_any
values: ["HubSpot", "Salesforce", "Pipedrive"]
source: builtwith
confidence_threshold: 0.75
trigger_signals:
- signal: "executive_hire"
role_pattern: "VP of Sales|Head of Sales|Chief Revenue Officer"
lookback_days: 90
source: linkedin_job_changes
weight: 3
- signal: "job_posting"
role_pattern: "SDR|BDR|Sales Development|Business Development Rep"
min_active_postings: 2
lookback_days: 45
source: linkedin_jobs
weight: 2
- signal: "no_outbound_infrastructure"
absence_of_tools: ["Outreach", "Salesloft", "Apollo", "Gong", "ZoomInfo Engage"]
source: builtwith
weight: 2
disqualifiers:
- field: "existing_role"
role_pattern: "VP Revenue Operations|Head of RevOps|Director of Sales Operations"
lookback_days: 180
source: linkedin_current_roles
disqualify: true
reason: "Internal RevOps capacity likely to self-build"
- field: "employee_count"
operator: greater_than
value: 750
disqualify: true
reason: "Org complexity typically slows initial evaluation cycle"
persona_routing:
primary_champion:
title_pattern: "VP of Sales|Head of Sales"
outreach_angle: "implementation_speed"
case_study_type: "ramp_time_reduction"
secondary_champion:
title_pattern: "Sales Operations|RevOps Manager"
outreach_angle: "system_integration"
case_study_type: "crm_hygiene_and_visibility"
scoring:
min_qualifier_match: 2
trigger_score_threshold: 5
disqualifier_overrides_score: true
metadata:
owner: "gtm-eng"
last_reviewed: "2026-09-01"
review_cadence_days: 30
linked_playbook: "playbooks/new-vp-sales-expansion.md"
A few things worth calling out in this schema.
Lookback windows are not optional
A VP of Sales hire that happened 18 months ago is not a signal. The window is the judgment, it reflects how long the pattern stays relevant before the opportunity has either been won, lost, or moved on. Encoding the window makes that judgment explicit and versioned.
Weights matter more than people expect
Not every signal carries equal conviction. A VP of Sales hire plus active SDR postings together cross the score threshold. Either one alone probably doesn't. The weights encode that logic so the system mirrors the instinct rather than treating every signal as equally important.
Disqualifiers are first-class citizens
Most scoring models I've seen bolt on negative factors as penalty weights, minus 10 points for this, minus 5 for that. The problem is that a disqualifier should be binary: if the RevOps leader already exists, you don't need to evaluate the rest of the rule. Treating them as overrides rather than deductions makes the schema cleaner and the behavior more predictable.
Persona routing belongs here, not in the CRM. The ICP isn't just about which accounts qualify, it's about who you reach at those accounts and with what angle. If you leave persona routing as rep judgment, you get inconsistency. If you encode it next to the qualifier logic, it stays current when the qualifier logic changes.
The Versioning Problem Nobody Talks About
Here's where most GTM engineering implementations quietly break down: ICP rules drift.
The account profile that closed well in Q1 is subtly different from the one closing well in Q3. New hiring patterns emerge. A competitor enters the market and changes the disqualifier logic. The product ships a feature that opens a new segment. The rule that was accurate when you wrote it is wrong eight weeks later, and nobody noticed because it was hardcoded in a CRM field or buried in a Clay table nobody's touched since the setup call.
The schema above has a version field and a last_reviewed date for a reason. ICP rules should be treated like code. They should live in version control. Changes should go through a review process, not because the marketing team needs to approve them, but because changing a qualifier silently affects everything downstream: the scoring model, the outreach triggers, the prioritization queue, the reporting.
In practice, I've seen teams manage this a few different ways:
Git + YAML files in a GTM config repo
The cleanest approach if your team has engineers who own GTM tooling. PRs for rule changes, a changelog, and you can diff two versions of your ICP against each other. The downside is it requires discipline, someone has to own the repo and keep it connected to whatever's running the rules.
Clay tables with a changelog convention
More accessible for non-technical GTM teams. Add a version column and a notes column to every qualifying table, update them on change, and maintain a log of what changed and when. Not as clean as Git but workable if the team is disciplined about it.
CRM custom fields
I've seen this work exactly once and I don't recommend it. CRM fields don't have version history, the audit log is usually off, and the moment two people can edit them simultaneously you've lost the source of truth.
Whatever approach you choose: the rule needs to live somewhere that changes to it are visible and intentional. An ICP that drifts silently is worse than a slide, because at least the slide doesn't claim to be running anything.
What This Doesn't Solve
Worth saying clearly: encoding the ICP as a rule schema solves the precision and consistency problem. It does not solve the judgment problem.
There are always going to be accounts that check every box and still feel wrong and a senior rep's instinct about that deserves respect even when the schema says qualify. There are going to be accounts that miss one qualifier and still close fast because a champion landed at exactly the right moment.
The schema is a filter, not an oracle. It's designed to handle the 80% of evaluation work that is genuinely pattern-matching, so that human judgment is reserved for the cases where it actually matters. The slide ICP vs rule ICP framing in the original piece puts it well: the slide describes accounts you've already decided were good; the rule set carries the reasoning that let you decide. The reasoning is what you're encoding. The final call is still yours.
Where to Start if You're Doing This Right Now
Don't try to encode your entire ICP at once. Pick the one pattern that has the clearest signal correlation, usually the one your best rep describes with the most specificity and build a single rule for it.
Run it in shadow mode against your last 90 days of pipeline. Compare what the rule would have prioritized against what actually closed. The gaps are your calibration data. Adjust the lookback windows, tune the weights, add the disqualifiers you missed.
Once the first rule is running and returning good signal, add a second. The schema above can hold as many rules as you need and as your understanding of your ICP evolves, the rules evolve with it.
Top comments (0)