Skip to content

feat(leads): qualify on public buying intent, not resemblance - #157

Merged
ralyodio merged 1 commit into
masterfrom
feat/intent-qualification
Jul 28, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/intent-qualification

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Acting on feedback that the expensive part of cold outreach isn't assembling a list — it's that writing to people with no demonstrated intent converts badly however good the copy is. Firmographics select for people who look like buyers, not people who are buying.

Intent = explicitness × recency

tier example weight
purchase "willing to pay", "budget of", "get a quote" 100
switching "migrating away from", "alternatives to" 85
solicitation "anyone recommend", "looking for a" 70
pain "struggling with", "sick of" 45

switching sits near the top deliberately: the budget already exists and the decision to spend it has been made.

Recency applies a half-life (36h) rather than a threshold — a 25-hour-old post isn't meaningfully worse than a 23-hour-old one, and a step function would rank them as if it were. An undated source takes a flat penalty instead of being assumed fresh, since most scraped entries have no date and would otherwise outrank a real post from yesterday.

Not just Reddit

Hacker News, Stack Exchange, Quora, Indie Hackers, X, LinkedIn, Mastodon/Bluesky, contract boards. A pipeline watching one community inherits its demographics as the entire market.

Everything except Reddit reads through the search index rather than a platform API — no per-platform auth, rate limits or review process. The honest cost, stated in the module: indexes lag, so this finds hours-old intent reliably and minutes-old intent only sometimes.

Three things it refuses

  • Intent on someone else's topic — "anyone recommend a good accountant, happy to pay" is flawless solicitation and worthless if you sell load testing
  • Anyone who said no — "no vendors please", "don't DM me", free-only. Answering them is the fastest way to lose a channel for everybody
  • Job ads — they read exactly like approved budget and aren't

A design error I made and corrected

My first pass filed intent hits as prospects. normalizeHost on a Reddit thread yields reddit.com — so every hit collapsed into one lead under the platform's domain, losing the person entirely. Signals are now their own table: a prospect is a company with an address, this is a person on a platform, and you reply where they asked.

Off by default

min_intent is null unless switched on, so no running campaign is silently emptied by a feature it never opted into.

Checks

  • tsc --noEmit clean · 1,073 tests pass (24 new) · build compiles
  • Migrations applied to prod

🤖 Generated with Claude Code

Feedback from someone who had already built a business on this premise:
the expensive part of cold outreach is not assembling a list, it is that
writing to people who have shown no intent converts badly however good
the copy is. Firmographic targeting does not fix that — it selects for
people who look like buyers rather than people who are buying.

So a campaign can now require evidence that somebody actually asked, and
those leads rank ahead of everything found by resemblance.

Intent is scored as recency times explicitness. A named budget outranks a
request for suggestions, which outranks a bare complaint, and someone
leaving their current supplier ranks near the top because the budget
already exists and the decision to spend it has been made. All of it
decays with a half-life rather than falling off a cliff at a threshold: a
25-hour-old post is not meaningfully worse than a 23-hour-old one.

Not only Reddit. The same sentence turns up on Hacker News, Stack
Exchange, Quora, Indie Hackers, X, LinkedIn and contract boards, and a
pipeline watching one community inherits its demographics as the entire
market. Everything except Reddit is read through the search index rather
than a platform API — no per-platform auth, rate limits or review, at the
cost of an indexing lag that makes hours-old intent reliable and
minutes-old intent occasional.

Three things the scorer refuses. Intent on somebody else's topic: a
flawless "anyone recommend an accountant, happy to pay" is worth nothing
to a load-testing company. Anyone who wrote "no vendors" or "don't DM
me", whatever else they scored — answering them is the fastest way to
lose a channel for everybody. And job ads, which read exactly like budget
and are not.

Signals are stored as signals rather than prospects. A prospect is a
company with a domain you can email; this is a person on a platform. My
first pass filed them as prospects and gave every Reddit thread the
target key "reddit.com", collapsing the queue into a single lead.

Off unless switched on, so no running campaign is silently emptied by a
feature it never opted into.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit e03ab79 into master Jul 28, 2026
8 checks passed
@ralyodio
ralyodio deleted the feat/intent-qualification branch July 28, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant