Audience: A small team (3-5 interns, or a handful of AI agents) working in parallel, each owning a slice of the work. Deliverable: A vetted list of 1,500-5,000 long-tail Rails-using companies across ten industry verticals, narrowed at the end to one chosen vertical with 500-1,500 ready-to-contact companies. Outcome it unlocks: Rick picks one vertical, contacts companies there, and builds toward ~100 customers for a product that helps Rails teams level up their AI use.
This guide explains what to do and why. It does not dictate what software to use. A shared Google Sheet, an Airtable base, or a SQLite file all work — pick whatever your team is comfortable with and stick to it.
Rick is running a sales campaign in April 2026. The product will help engineering teams that already use Ruby on Rails get better at AI-assisted development (Claude Code, MCP, agents, infrastructure). Before he commits to one niche, he needs to see which verticals actually have enough findable Rails companies to be worth targeting, especially the long-tail (smaller, less-visible shops — not the GitHub/Shopify/Stripe whales).
The usual research sources (RailsConf sponsor decks, the front page of Hacker News) over-represent a handful of famous companies and miss the small ones. That’s the problem this project solves.
A company counts as long-tail if it has both:
We’re not excluding bigger companies — they still get logged. But “long-tail fit” is a separate flag that drives the final niche pick.
Every company gets classified into exactly one of these ten buckets. Full definitions with examples are at the end of this doc (see §12).
These ten are non-negotiable — it’s how the output stays comparable with industry reports.
PHASE 1: Cast the wide net (1-2 weeks of team time)
Goal: 1,500-3,000 companies surfaced across all 10 verticals
↓
PHASE 2: Rick picks one vertical (1 session, ~1 hour)
Goal: a single niche chosen, based on a scorecard the team produces
↓
PHASE 3: Deep dive in the chosen vertical (few days)
Goal: 500-1,500 vetted long-tail rows in that one vertical
↓
(Later, out of scope) — contact discovery and outreach
Phase 1 is the bulk of the work. Phase 3 is higher judgment per row. Phase 2 is a decision meeting Rick runs.
Everyone works in one shared spreadsheet (or equivalent). These are the required columns — you can add your own notes columns if useful, but don’t rename or reorder these.
| Column | Meaning | Who fills it |
|---|---|---|
company_name |
Company’s real name | Finder |
domain |
Canonical web domain, lowercase, no www., no trailing slash (e.g., acme.com) |
Finder |
source |
Where we found them — one of: github, hn-hiring, wwr, remoteok, job-board-dork, rails-foundation, conference-sponsor, gem-maintainer, web-search |
Finder |
signal_type |
What kind of evidence — job_post, code, sponsor, blog, gem_maintainer, web_mention |
Finder |
signal_date |
Date of the evidence in YYYY-MM-DD. Leave blank if unknown. |
Finder |
evidence_url |
Link to the exact job post / sponsor page / code / blog | Finder |
raw_text |
1-3 sentences of context from the evidence — job title, description snippet, or quote | Finder |
primary_vertical |
One of the ten verticals. Classifier fills this. | Classifier |
business_model |
One of: marketplace, b2b_saas, dev_tools, vertical_saas, internal_tools, media, consumer. See §13. |
Classifier |
headcount_tier |
XS <20, S 20-100, M 100-500, L 500-2000, XL 2000+. Leave blank if unknown. |
Classifier |
long_tail_fit |
yes / no / unknown — computed: yes if headcount is XS/S/M AND company is NOT a conference sponsor. |
Classifier |
confidence |
0.0 to 1.0 — how sure the classifier is. 0.9+ only if the evidence explicitly names the industry. | Classifier |
audit_verdict |
agree / disagree / unclear — Rick (or auditor) fills this on sampled rows. |
Auditor |
Dedupe rule: The unique key is domain. If two people find the same company, merge into one row; append the second evidence_url to a notes column rather than creating a duplicate row.
The work splits cleanly into three roles. A person (or agent) can do more than one, but on any given row, these are different passes.
primary_vertical, business_model, headcount_tier, long_tail_fit, confidence. They can use an LLM (ChatGPT / Claude) to batch-classify dozens at once by pasting rows in — but they must spot-check the output.audit_verdict. This keeps the classifier honest.A team of three people can reasonably split: one does GitHub + job boards, one does conferences + foundation + gems, one does the exploratory web search. Then one person classifies after the evidence is all in. Then Rick audits.
Goal: 1,500-3,000 company rows in the tracker, evidence-backed, classified into the ten verticals.
There are six source families. Spend your budget in roughly this order of payoff (first listed = highest ROI).
Why: Direct evidence a company is actively writing Rails code today.
How:
https://github.com/search.gem "rails" with language filter Ruby and filename filter Gemfile.→ add the company to the tracker. Source = github, signal_type = code, evidence_url = the repo URL, raw_text = "Found 'gem \"rails\"' in <org>/<repo>/Gemfile". Signal_date = today (the check date).
Target for Phase 1: ~300-500 companies from this source.
Why: If someone is paying to hire a Rails engineer right now, they’re actively running Rails.
How (run each of these):
HN “Ask HN: Who is Hiring?” threads, last 12 months. Find them via https://hn.algolia.com/?query=Who%20is%20hiring (filter: Stories, last year). Each thread has hundreds of comments; scroll or use browser search for “Rails” or “Ruby on Rails”. Comments typically start with the company name and a URL — grab both.
We Work Remotely. Category: “Remote Ruby on Rails Jobs” (https://weworkremotely.com/categories/remote-ruby-on-rails-jobs). Walk the listings; each job has a company name.
RemoteOK. https://remoteok.com/remote-ruby-jobs — similar, one row per job.
Google dorks against hiring platforms:
site:boards.greenhouse.io "Ruby on Rails"site:jobs.lever.co "Ruby on Rails"site:jobs.ashbyhq.com "Ruby on Rails"Each result URL contains a company slug (e.g., boards.greenhouse.io/acmeco/... → company slug = acmeco). The slug is usually close to the real company name.
For each hit:
hn-hiring / wwr / remoteok / job-board-dork as appropriate.job_post.Target for Phase 1: ~500-1,000 companies from this source.
Why: Paying the Rails Foundation is a strong “we run Rails at scale” signal.
How: Visit https://rubyonrails.org/foundation/. Scrape each logo tile for company name + URL. Add all of them to the tracker with source = rails-foundation, signal_type = sponsor.
Target for Phase 1: 30-60 companies (it’s a small directory).
Why: Conference sponsors are actively invested in the ecosystem.
How: Visit each of these pages and list every sponsor logo with its URL:
Source = conference-sponsor, signal_type = sponsor, signal_date = the conference year (use YYYY-01-01).
Target for Phase 1: 100-200 companies.
Why: If a company’s engineers maintain a popular gem, that company almost certainly runs Rails in production.
How:
https://rubygems.org/stats. Get the top ~500 gems by total downloads.source_code_uri or homepage_uri.github.com/<org>/... and <org> is NOT an individual (i.e., it’s an organization with its own domain), note the company.Source = gem-maintainer, signal_type = gem_maintainer.
Target for Phase 1: 50-150 companies.
Why: Sources 1-5 are structured and miss anything that doesn’t fit their mold — regional companies, bootstrapped shops that don’t hire publicly, stealth startups.
How: Run these queries (substitute the vertical name):
"built with Rails" <vertical> site:*.com -github.com"our Rails app" <vertical> "engineering blog""Ruby on Rails" <vertical> "case study" — pull from Rails consultancy sites (thoughtbot, Planet Argon, Test Double, Crowd Favorite, Arkency)"Ruby on Rails" <vertical> podcast — pulls guest appearances on Remote Ruby, Code with Jason, etc."Ruby on Rails" <vertical> site:dev.to — blog postssite:reddit.com/r/rails <vertical> — Reddit posts where people mention employersSource = web-search, signal_type = web_mention. This is the noisiest source. Read each hit carefully before adding — easy to misattribute. Audit 15-20% of web-search rows (higher than other sources).
Target for Phase 1: 500-2,000 rows (it’s the largest source by volume).
After 100+ rows, stop searching and classify what you have. You can batch-paste 50-100 rows into Claude or ChatGPT with the vertical definitions (§12) and the business-model taxonomy (§13) and ask it to return vertical + business_model + confidence for each. Spot-check the output (see §9).
evidence_url).disagree rate is under 20%.Goal: Rick picks one vertical to pursue. Takes about an hour.
For each of the ten verticals, fill in this table (SQL pivots or a spreadsheet pivot works equally well):
| Vertical | Rails density | Activity | Long-tail fit | Warm-network overlap | Competitive density | |—|—|—|—|—|—|
signal_date is within the last 365 days.long_tail_fit = yes.RICK_GORMAN_PROFILE.md).No formula picks the niche. Rick looks at the scorecard and weighs:
Output: a short writeup (in the same strategy doc or a new NICHE_PICK.md) that names the vertical, the score across dimensions, and 3-5 sentences of rationale.
Phase 1’s classifier output must be sampled. Here’s who gets audited:
source=web-search rows — the noisiest source.For each sampled row, the auditor reads the evidence_url, reads the classifier’s label, and sets audit_verdict:
agree — classification is right.disagree — classification is wrong. The auditor writes the correct primary_vertical in the same row and changes confidence to 1.0.unclear — evidence is too thin. Leave the row but flag long_tail_fit = unknown.Stop and regroup if the disagree rate in any vertical is above 30% — the classifier prompt or the evidence quality is bad, and you need to fix it before Phase 2.
Goal: A curated, human-verified list of 500-1,500 long-tail companies in the one chosen vertical. This is the list Rick will actually reach out from.
The important difference from Phase 1: No LLM-assisted classification. Rick (or a human) reads every row before it stays on the list.
Open each of the six sources from Phase 1 again, but add the vertical’s own keywords to the queries. Examples:
HIPAA, FHIR, EHR, clinical, patient to your GitHub searches and job-board dorks.fintech, banking, payments, KYC, AML.developer experience, CI/CD, observability.This surfaces the vertical-specific subset that was buried in Phase 1’s breadth.
These are only useful after the niche is chosen. A few examples per vertical:
Add a new source value for each (e.g., himss, klas). Record evidence the same way.
Go through every row. Remove:
L or XL) — unless Rick wants an enterprise sub-list.For each surviving row, set classified_by = human:<name> and confidence = 1.0.
For each row, spend ~30 seconds looking up:
"<company name>" site:linkedin.com/company).Fill those three columns. Do not yet try to find named individuals — that’s a later phase.
500-1,500 rows in the chosen vertical, all manually reviewed, with audit_verdict = agree or classified_by = human:<name>.
Export to deep_<niche>.csv and hand to Rick.
Pick the vertical that matches the dominant product the company sells.
If a company genuinely straddles two (e.g., Stripe does both BFSI and IT/Telecom), pick the one where the paying customer’s industry lives. Stripe → BFSI (their customers are financial use cases). GitLab → IT/Telecom (their customers are IT organizations).
Orthogonal to the vertical. Used for the pivot views in Phase 2.
Phase 1 handoff (from Finders/Classifiers to Auditor):
evidence_urlprimary_vertical and business_modelPhase 2 handoff (from Auditor to Rick):
Phase 3 handoff (from deep-dive team to Rick):
audit_verdict = agree or classified_by = human:<name>deep_<niche>.csv and share with RickAfter that, the project moves into contact discovery and outreach — separate strategy document, separate team.
| Phase | Person-hours (3-person team) | Elapsed time |
|---|---|---|
| Phase 1 — breadth-first discovery + classification | 30-50 hours total | 1-2 weeks |
| Phase 1 — audit | 3-5 hours (Rick) | Half a day |
| Phase 2 — scorecard + niche pick | 1-2 hours (Rick) | 1 meeting |
| Phase 3 — deep dive + manual review | 15-25 hours total | Several days |
If the team shrinks to 1 person, multiply by ~2.5 because of lost parallelism.
Escalate to Rick immediately if you hit any of these:
disagree rate in a vertical stays above 30% after one pass of fixes.Don’t fabricate data. Don’t silently drop rows. Don’t skip the evidence URL. The whole project’s value depends on the signal being real.