The DevTool Outreach Queue: From GitHub Activity to Ranked Sends
You will be able to stand up a weekly pipeline that captures GitHub activity, resolves actors to companies and reachable contacts, dedupes, gates for lawful send, and outputs a ranked queue.
This guide is for founders selling a developer tool, account executives, SDR leads, and partnerships teams who want to turn a week of GitHub activity into pipeline. The job is narrow and repeatable: take the stars, forks, issues, pull requests, and dependency adoption across your repo and your competitors' repos, resolve each actor to a company and a reachable contact, dedupe across events, gate every record on lawful send, and hand reps a ranked queue. What follows is the full pipeline, in order, with what to do at each stage, how long it takes, and what a good result looks like.
Two facts shape every decision here. First, since July 2026 GitHub restricts stargazer-listing endpoints to repo admins and collaborators, so a stars-first design is now the most fragile thing you can build. Second, the events feed excludes anything older than 30 days, which turns cadence from a nice-to-have into the load-bearing part of the system.
What this pipeline captures and where the data comes from
The pipeline captures typed GitHub events plus dependency adoption, resolves each actor to a person and a company, and outputs a deduped, lawful-send, ranked queue. The durable source is the Events API, not stargazer lists.
GitHub's public activity is exposed through the Events API, which returns typed events including WatchEvent (a star, with action started), ForkEvent, IssuesEvent, and PullRequestEvent. You can read them per repo, per org, per user, or across the public network for a repo. Each event carries a stable numeric actor.id, a mutable login, the repo, the type, and a created_at timestamp. That numeric ID is the primitive the whole pipeline hangs on, because logins change and IDs do not.
Stars used to be the obvious entry point. They are not anymore. Since July 2026, stargazer-listing endpoints are limited to admins and collaborators, and the subscriber and watched-repos endpoints are similarly restricted or being deprecated. For your own repo you can still list stargazers; for a competitor's repo you cannot. The path that works uniformly across every repo is WatchEvent from the Events API, which reports a star as it happens without touching the restricted listing.
Dependency adoption is the other high-value signal, and it is messier. For public repositories the dependency graph lists dependents, meaning other public repos that depend on your package. It is not reported for private repos, the counts are approximate, and the numbers may not match the listed dependents. Treat it as a candidate list of adopting organizations, not a ledger.
Why events beat stars, and what each event fails to prove
Context-rich events beat raw stars because a fork or a feature-request issue exposes a company and a use-case, while a star exposes only a mutable username. That is the whole argument for how you rank intent.
No regulator or neutral body publishes a canonical intent ranking. This is practitioner opinion, and I will label it as such. Vendors converge on the same mechanism: knowing who opens issues about enterprise features, forks with company-specific changes, or authors pull requests at well-funded companies beats knowing who clicked a star. A star indicates popularity and awareness. It does not prove evaluation, and it certainly does not prove authority to buy.
A defensible heuristic ordering, highest intent first:
| Signal | What it proves | What it looks like when it lies |
|---|---|---|
| Dependency adoption | An org ships your package in production | Approximate count includes phantom or abandoned dependents |
| Pull request | Hands-on use, often at a named company | A one-line typo fix from an unaffiliated hobbyist |
| Feature-request issue | An evaluation with a specific need | A support question from a student or tire-kicker |
| Fork with context | Company-specific changes and a visible actor | A fork made to read code, never touched again |
| Star | Awareness only | A vanity star from someone who never returns |
Read this as a heuristic, not a law. A canonical, evidence-backed ordering is not established publicly. The mechanism is what makes it defensible: the further down the list you go, the less the event tells you about the person behind it.
A star exposes a mutable username. A fork exposes a company and a use-case.
Sizing the audience: who could this repo actually reach
Before you work a queue, size the pool it draws from, because pool size sets the ceiling on your weekly throughput and reveals where the lawful-send gate will bite hardest.
In Refolk's index of professional profiles, the addressable engineer pool varies sharply by skill and market. These are the numbers I use to set expectations for a devtool aimed at a given ecosystem.
| Segment | Count | Derived vs US Go |
|---|---|---|
| Go, Software Engineer, US | 2,766 | 1.00x |
| Go, Software Engineer, Germany | 304 | 0.11x (US is 9.1x) |
| Rust, Software Engineer, US | 606 | 0.22x (US Go is 4.6x) |
Two things fall out of this table. The US Go pool is about 9.1 times the German Go pool and about 4.6 times the US Rust pool. And raw pool size is misleading the moment you factor in the send gate. A German pool of 304 looks small but is workable by hand in an afternoon; the same effort against a 2,766-strong US pool hits the rate limit, not the enrichment budget.
Germany inverts the usual "biggest market first" instinct. Germany effectively requires prior consent and bars personal-address legitimate-interest sends, so the sendable German queue is far smaller than its pool suggests. When you sequence markets, let the gate, not TAM, decide volume.
The weekly pipeline, start to finish
Run this end to end once a week. Each step lists the owner, rough duration, and what "done" looks like. The whole run is designed to be executed by hand for a small monitor set or scripted for a large one.
The weekly run
- Configure the monitor setVersion a list of your repo plus 3 to 10 competitor or adjacent repos and the event types you will capture. Rely on the Events API for competitor repos, since stargazer listing is admin-only. Done when the list and scope are in source control.
- Capture the week's eventsPoll the Events API with ETags to conserve quota, respecting the five-minute delay and the 30-day, 300-event window. Done when you have raw rows with actor.id, login, repo, type, and created_at.
- Add dependency-adoption signalsPull dependent orgs and repos from the dependents view for each package. This is UI-derived and approximate. Done when you have a candidate list of adopting organizations.
- Resolve actors to peopleSpend 2 to 5 API calls per actor for name, company text, location, website, and a candidate email from recent commits. Flag noreply-only commits as unresolved-email. Done when every actor has a person record or a flag.
- Resolve people to accounts and contactsNormalize free-text company to a domain and attach a verified business email and role. Done when each resolvable person maps to a company account with a reachable contact.
- DedupeCollapse to one record per numeric actor.id, bundle event types into a single record keyed to the highest-intent signal, and merge accounts by domain. Done when no actor.id or domain repeats.
- Apply the lawful-send gateTag each record with jurisdiction, basis, email type, published status, and suppression status. Drop personal-address EU and German records and unpublished-address Canadian records. Done when every record is send-eligible.
- Score and rankOrder by intent tier times account fit times recency, weighting dependency, PR, and feature-issue above stars, decaying records past 3 to 6 months. Done when the queue is sorted send-first.
- RouteHand each rep a record with owner, signal citation, and opt-out wired, sending VIP maintainers to founders. Done when every top record has an owner and a suppression check.
The single most important discipline here is that steps 2 through 9 must run every week without a gap. Events older than 30 days are excluded even when the timeline holds fewer than 300 events. Skip a week and the actors from that gap are gone permanently, with no backfill. The pipeline's value decays to zero without a standing run.
What survives each stage of a weekly run
- 2,766Captured events
US Go pool as an illustrative ceiling
- 606Actors resolved to a person
identity resolves readily; email is the drop-off
- 304With a reachable business email
noreply and personal addresses removed
- 200Passing the lawful-send gate
jurisdiction and email-type gate applied
The funnel figures are illustrative counts drawn from the Refolk pool sizes to show the shape of the narrowing, not a measured conversion rate for any one repo.
Rate limits set your real throughput
Rate limits, not enrichment cost, cap how many leads you can resolve. At 4 to 5 API calls per lead against a 5,000-per-hour authenticated ceiling, one token tops out near 1,000 resolved leads per hour.
| Method | Limit/hour | Approx leads/hr at 5 calls each |
|---|---|---|
| Unauthenticated | 60 | ~12 (derived) |
| PAT / OAuth | 5,000 | ~1,000 (derived) |
| GitHub App on GHEC | 15,000 | ~3,000 (derived) |
Manual prospecting works for your first 50 or so leads, then the cost is prohibitive: paginating events, calling the users endpoint per handle, deduping against CRM, and checking existing customers runs 4 to 5 API calls per lead against that hourly ceiling. This is exactly why the German Go pool of 304 is a manual afternoon and the US Go pool of 2,766 is not.
There are two practical levers. Authenticate with a personal access token or OAuth to get 5,000 requests per hour instead of 60. If you operate a GitHub App owned by a GitHub Enterprise Cloud org, you get 15,000. And poll with ETags so unchanged responses do not count against your quota. Respect the five-minute delay on the public feed and the up-to-six-hour event latency when you reason about freshness.
Resolving an actor to a company and a reachable contact
The documented procedure is to take the actor's login, retrieve the GitHub profile for real name, company, location, and website, then enrich against public professional records and work-email lookups to produce a lead record. Identity resolves readily. Email discoverability is the bottleneck.
Email typically comes from searching the user's recent commits, the last 30 days or commits in repos they own, then adding company and role via enrichment, and flagging power users such as maintainers of repos with more than 50 stars. Two blockers recur. First, many users commit under a noreply address: accounts created after July 18, 2017 use the form ID+USERNAME@users.noreply.github.com, which is a valid string and an undeliverable mailbox. Second, the profile "company" field is free text, not a resolved account, so "freelance", "@ex-employer", or a joke will map to the wrong domain if you trust it verbatim.
Plan for meaningful drop-off. A GitHub-specific email discovery rate is not established publicly. The only adjacent published figure comes from a different pipeline claiming 65 to 80 percent discovery at $6.49 per run, which I cite only to set expectations, not as a benchmark for this job.
When the resolution step is the part eating your week, this is where Refolk removes the friction: you describe the actors you want in plain English and get people already resolved to a company and a reachable contact, so you spend your rep hours on ranking and sending rather than on chasing noreply addresses.
Dedupe on the ID, never the login
Collapse to one record per numeric actor.id, bundle a person's event types into a single record keyed to the highest-intent signal, and merge accounts by domain. No published dedup standard exists for this job, so the rules below are derived from GitHub's own data model.
The load-bearing fact is that events carry a stable numeric actor.id while the login is mutable. If a user renames their account, login-based dedup creates a duplicate record and a second cold email to the same person. Worse, a user who commits under a noreply address and then changes their username de-links those commits from the account entirely, so identity threads that look separate may be one person.
Three dedup rules, in order:
- Person level: one record per numeric
actor.id. Never key on login. - Signal level: one signal-bundle per person per window, keyed to the highest-intent event. Someone who starred, forked, and opened a feature issue is one record ranked at the feature-issue tier.
- Account level: collapse people whose resolved emails share a domain into one account, so five engineers at the same company do not read as five accounts.
The lawful-send gate every record must pass
Before a record reaches a rep, tag it with jurisdiction, legal basis, business-versus-personal email, published-versus-not, and suppression status. A real buying signal does not make an email lawful to send.
Three frameworks govern most of your queue. Map every record to the right one before scoring, because a record that fails the gate should never earn rank.
| Jurisdiction | Consent model | Non-personal-email gate |
|---|---|---|
| US (CAN-SPAM) | Opt-out; no prior consent | Not required; needs sender ID, physical address, and opt-out |
| EU/UK (GDPR) | Legitimate interest plus a documented assessment | Business email and role-relevant; personal domains not defensible |
| Canada (CASL) | Consent before the first send | Address must be conspicuously published |
For B2B in the EU, the legal basis is legitimate interest under Article 6(1)(f). If you pass the three-part test, meaning a real commercial reason, processing that is necessary, and interests that do not override the contact's, you can email EU business contacts without prior consent. Two hard gates cut into that. You cannot email personal addresses such as gmail.com under legitimate interest for cold B2B in most member states, and Germany applies national rules that effectively require prior consent. For Canada, an address must be conspicuously published to qualify for CASL implied consent; if an individual did not publish their email for professional contact, cold outreach is difficult to justify.
The operational duties are the same everywhere: a visible one-click unsubscribe with opt-outs suppressed immediately, a permanent suppression list checked against every send, and a documented data source with legitimate-interest reasoning for the EU. The stakes are not theoretical. CAN-SPAM penalties have been cited up to $53,088 per email, GDPR fines reach €20M or 4 percent of global revenue, and CASL runs up to CAD $10M per violation.
jurisdiction: US | EU/UK | Canada | other legal_basis: CAN-SPAM opt-out | GDPR legitimate interest (LIA on file) | CASL published-consent email_type: business_domain | personal_domain | noreply (reject) published_for_contact: yes | no suppression_checked: yes (date) | no
Attach these five tags to every record; drop any that fail before scoring.
Score, rank, and route
Order the queue by intent tier times account fit times recency, weighting dependency, PR, and feature-issue signals above stars, and decaying records older than 3 to 6 months. Route the top of the queue to reps and the VIP maintainers to founders.
Recency is not optional. Stars older than 3 to 6 months rarely convert because developers move on, so a record's rank should decay with age and drop out past that window. Working a six-month-old star wastes rep time on someone who has already made a decision.
Where a resolved record lands
Route with a signal citation attached so the rep opens with the actual event, not a generic pitch. A message that references the specific pull request or feature issue reads as informed; one that references "your interest in our project" reads as scraped.
Subject: your [feature-request issue] on [repo] Hi [first name], I saw you [opened an issue about X / forked repo with company-specific changes] last week. That is usually a sign a team is evaluating [use-case]. If that is where [company] is, I can share how others solved it. If not, tell me to close the loop and I will. Unsubscribe: [link].
Swap the bracketed context for the record's real signal citation; never send with the brackets in place.
How this pipeline goes wrong
The failure modes below are the highest-value part of this guide, because each one produces a queue that looks complete and correct while quietly leaking or misleading. For each, I give the false positive and the check that catches it.
- Star capture silently breaks. After the July 2026 restriction, stargazer-listing calls on repos you do not own return limited data, and an empty diff reads as "no new stars." Check: reconcile against
WatchEventcounts from the Events API. - A stale queue looks fresh. The 30-day, 300-event cap plus up-to-six-hour latency means a weekly run misses high-volume repos, and a "complete" week may have dropped events beyond 300. Check: if the event count hits the cap, shorten the polling interval.
- Noreply email treated as reachable. Commits under
users.noreply.github.comyield a valid-looking, undeliverable address. Check: reject any address on the noreply domain before routing. - Company field trusted verbatim. Free-text "company" resolves to the wrong account. Check: require a normalized domain plus independent confirmation before assigning an account.
- Dedupe on login, not ID. A renamed user creates a duplicate record and a second cold email. Check: key on numeric
actor.id. - Legitimate interest assumed globally. Sending to a personal-domain EU contact, or any German contact without consent, fails the gate even when the star is real. Check: apply the jurisdiction and email-type gate before scoring.
- Dependent counts over-trusted. Approximate dependents inflate adoption tiers. Check: verify the dependent org exists and ships the package before scoring it top-tier.
- Stale stars ranked high. Working six-month-old stars wastes rep time. Check: apply recency decay and drop beyond 3 to 6 months.
Verify before you call it done
Run this checklist against the finished queue each week. If any item fails, the queue is not send-ready, no matter how good the signals look.
Weekly queue sign-off
- Every star was captured as a WatchEvent, not from a stargazer-listing call, and counts reconcile.
- The run happened inside the 30-day window with no skipped week, and no repo hit the 300-event cap unnoticed.
- Every record is keyed to a numeric actor.id, with event types bundled and accounts merged by domain.
- No record carries a noreply-domain address or an unverified free-text company.
- Each record is tagged with jurisdiction, legal basis, email type, published status, and a same-week suppression check.
- Personal-address EU and German records and unpublished-address Canadian records are dropped.
- Ranking weights dependency, PR, and feature-issue above stars, and records past 3 to 6 months are decayed or dropped.
- Every top record has an owner, a signal citation, and a wired opt-out, with VIP maintainers routed to founders.
Keeping the pipeline current
Treat the pipeline as a standing system, not a one-off pull. The two things most likely to change out from under you are GitHub's access rules and the send-compliance landscape, so build a habit of re-checking both.
Re-verify the endpoint access model on a schedule. The July 2026 restriction on stargazer and subscriber listings is the kind of change that breaks a pipeline silently, and GitHub has adjusted the events window before, cutting it from 90 to 30 days in January 2025. If your capture counts drop without an obvious cause, check whether an endpoint moved behind an auth wall before you assume the repo went quiet. Re-check the lawful-send gate whenever you enter a new market, because the jurisdiction rules, not your pool size, decide how much of a market you can actually work. Do those two reviews and the rest of the pipeline runs itself, one week at a time.
Questions practitioners ask
Can I still pull a competitor's stargazer list for prospecting?
Not reliably. Since July 2026, GitHub restricts stargazer-listing endpoints to repo admins and collaborators, so calls against repos you do not own return limited or blocked data. Build capture on the Events API instead, where a star arrives as a WatchEvent with action started. You get the actor and timestamp without needing the stargazer listing, and it works the same across your repo and competitor repos.
How many leads can one GitHub token resolve per hour?
Roughly 1,000, derived from the 5,000-requests-per-hour authenticated limit and 4 to 5 API calls per lead. Unauthenticated access is capped at 60 requests per hour, or about 12 leads. A GitHub App on a GitHub Enterprise Cloud org gets 15,000 requests per hour, around 3,000 leads. Manual prospecting breaks down past roughly 50 leads regardless, once CRM deduping and customer checks are included.
Why does the events window matter so much for cadence?
Because events older than 30 days are excluded even when the timeline holds fewer than 300 events. A team that skips a week permanently loses the actors from that gap, since there is no way to backfill beyond the window. High-volume repos can also hit the 300-event cap inside a week. If you see the cap, shorten the polling interval so you do not silently drop events.
Is it legal to cold email a developer I found from a GitHub star?
It depends on jurisdiction and email type. Under GDPR you need legitimate interest plus a documented three-part test, and personal-domain addresses are not defensible in most member states. Germany effectively requires prior consent. Canada's CASL requires the address be conspicuously published. US CAN-SPAM allows opt-out sending with honest sender identification. Gate every record on jurisdiction and email type before it reaches a rep.
Should I trust the dependent counts shown on GitHub?
Treat them as approximate. Dependents are only computed for public repositories, and GitHub states the counts may not match the listed dependents. Use the list to find candidate adopting organizations, but verify each org actually exists and ships the package before scoring it top-tier. Over-trusting raw dependent counts inflates your adoption tiers and wastes rep time on phantom accounts.
What is the biggest reason a resolved contact turns out to be unreachable?
The noreply email. Accounts created after July 18, 2017 commit under an ID+USERNAME@users.noreply.github.com address, which is syntactically valid but undeliverable. Reject any address on the noreply domain before routing. Identity resolution is rarely the bottleneck; email discoverability is. Plan for meaningful drop-off at the email step, and do not let a valid-looking noreply address pass into a send queue.
Try it on your own search
Stop building boolean strings. Just describe the person.
Type one sentence and I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web live, then hand back a ranked shortlist with the reasoning behind every name. No filters to learn, no export to clean up, no sales call to sit through.
- One sentence in, a ranked shortlist out. No boolean, no filters, no seat to buy.
- Read live at search time, not from a database that went stale last quarter.
- Watch every step as it runs, and see why each name made the list.
- Staff backend engineers in NYC who shipped Rust in production
- Series A fintechs in SF under 50 people, growing headcount this year
- Maintainers of fast-growing Rust web frameworks on GitHub
500 free credits on sign-up. No card, no demo call. See real searches.