The Contributor Sourcing Teardown: One Repo to a Cleared, Ranked Slate
Take one repo from its headline contributor count to a ranked, contactable slate of 15-25 people, with every cut logged and three list-distorting wrong turns avoided.
Key takeaways
- GitHub's contributors graph shows only the top 100 contributors and the REST API links only the first 500 author emails, so a large project's default view hides most of its authors unless you pass anon=true or run git shortlog.
- Casual contributors, defined as people with at most one commit, are 48.98% of contributors but author only 1.73% of commits in Pinto et al.'s study of 729 projects.
- Counting by pull requests instead of commits raises the casual group's share of accepted contributions from 1.73% to 12.5%, so a commit-only cut can throw away real contributors on squash-merge projects.
- In the Rust project, 272 core developers (7.0%) wrote 80% of commits, and 20.2% of that core was paid by an employer against 4.8% to 5.8% elsewhere, which is why commit-sorted lists are front-loaded with staff.
- Copilot coding agent commits name Copilot as author and the human as co-author, so deleting bot-authored commits without parsing Co-authored-by lines erases real people from the list.
- In Refolk's index only 124 people in the United States put "open source maintainer" in their headline, and 8 of a 25-person "core contributor" sample hold founder or executive titles, so headlines cannot replace repo evidence.
Someone has told you to "go hire from the contributors to the framework we run on." This guide is for in-house recruiters, sourcers, talent leaders and founders hiring for themselves. It takes one project's contributor list down to a ranked slate of 15-25 real, reachable, hireable people. A single worked example runs through every cut using the counts that have actually been published, says plainly where no published count exists, and names the three wrong turns that quietly inflate or hollow out the list.
What does the Contributors tab actually show?
The Contributors tab shows at most the top 100 contributors. It leaves out merge and empty commits, and it drops anyone whose commits aren't on the default branch or whose authoring email isn't linked to a GitHub account. The REST API reaches further, but it links only the first 500 author emails to users. Everyone after that comes back anonymous, and only if you ask for them.
Every GitHub contributors list you start from is shaped by these four limits:
| Surface | Limit | Effect |
|---|---|---|
| Contributors graph | Top 100 | v8: 100 of 633 visible (15.8%, derived) |
| Contributors graph | Under 10,000 commits | No insights at all above that |
| REST contributors endpoint | 500 linked emails | Rest anonymous unless anon=true |
| Graph and API | Email linked to an account | Unlinked authors dropped |
Source: GitHub documentation and GitHub community discussion #174034.
The documented case is v8/v8. It has 633+ contributors, but the graph shows only the top 100 by all-time commit count. GitHub staff have said that on larger repos you may not be able to reproduce the figure shown on the website. Nobody has published a systematic comparison of these surfaces against a full git log deduplicated by name and email. So the ground truth is the deduped author list you build yourself from the git history, not any number GitHub displays.
Wrong turn 1: stopping at the graph. The tail beyond 100 disappears, and on big repos everyone past the 500th linked email disappears too unless you pass anon=true. The list looks clean and ranked. It's actually a sample biased toward the heaviest committers, who, as later sections show, are disproportionately people you can't hire.
The worked example: the Rust project, cut by cut
The worked example is the Rust project as classified in Zhang et al.'s paid-versus-volunteer study (ICSE 2024). I chose it because it's the one case in the evidence where a published study sorted the entire author population into one-time, peripheral and core groups and tagged who was paid by an employer. That means the intermediate counts below are real, not invented. Where the study gives no count for a cut, I say so and show what you would log on your own repo.
The study defines core developers as the people who together account for 80% of commits. Everyone else is peripheral, and one-time contributors are their own group. Here is the running cut log:
| Cut | Count | Where it comes from |
|---|---|---|
| All classified authors | about 3,900 | Derived: 272 core is 7.0% |
| One-time, set aside | about 1,300 | Derived remainder |
| Peripheral | 2,313 | 133 paid plus 2,180 volunteers |
| Core (80% of commits) | 272 | Zhang et al. |
| Core paid by an employer | 55 | 20.2% of core |
| Core volunteers | 217 | Derived: 272 minus 55 |
Source: Zhang et al., ICSE 2024. The derived rows are my arithmetic. The total depends on rounding in the 7.0% figure, so treat it as approximate.
The Rust project, from all authors to a slate
- ~3,900All classified authors
derived from 272 being 7.0%
- 2,585Peripheral plus core
one-time contributors set aside
- 272Core, 80% of commits
Zhang et al.
- 217Core volunteers
55 paid moved to an employer check
- 15-25Ranked slate
after ownership and contact cuts
Your repo will have different numbers, but the shape carries over: a large casual tail, a small core doing most of the work, and paid staff clustered in that core.
The procedure: headline count to ranked slate
The method is eight cuts, run in order, with each count written to a log before the next cut starts. By my own unsourced estimate, a single repo takes about ten hours end to end, and most of that goes on the employer split, the ownership check and contact clearance.
From one repo's contributor list to a ranked slate
- Record the headlineLog the repo's displayed contributor count and the size of the graph list, which is never more than 100. Done when both numbers are in the cut log.
- Recover the hidden authorsPage the REST contributors endpoint with anon=true, or clone and run git shortlog -sne on the default branch, then dedupe by name and email. Done when you have one row per human with a commit count.
- Remove bots and agents, keep their humansFilter [bot] logins, head:copilot/ branches, Agent-Logs-Url trailers and agent Co-authored-by lines, then credit agent commits to the human co-author. Done when the removed and re-credited counts are logged.
- Separate casual contributorsSet aside anyone with one commit or fewer, then optionally apply the 80%-of-commits core cutoff, re-running by merged PRs on squash-merge repos. Done when casual, peripheral and core counts are logged.
- Split by employerMark sponsor employees and off-limits employers using org membership, email domain and the profile company field, requiring two signals to agree. Done when every core row has an employer status.
- Identify subsystem ownersUse CODEOWNERS, MAINTAINERS files and review counts on merged PRs, and write your threshold into the log. Done when every remaining row is marked owner or contributor, with a path.
- Confirm a permitted contact pathUse only an email or link the person has published on their profile or personal site, and log any do-not-contact request. Done when every slate member has a cleared path or is dropped.
- Rank to a slate of 15 to 25Order by ownership, then sustained contribution, then fit to the role, and cut at 25. Done when the slate is ranked and every row traces back to a logged cut.
No source settles whether the employer split should come before or after the casual cut. I run the casual cut first. Employer attribution is the slowest, most manual step, and there's no point attributing employers for a thousand people who made one commit each. If your sponsor is huge and its staff make up most of the list, you can reverse the order.
If you only need the basics of reading the graph, the shorter contributor graph to shortlist guide covers them. This guide adds a count to every cut and the contact rule.
How do you recover hidden authors and remove bots without deleting people?
Build the author list from git history on the default branch, merge rows that belong to the same human, and then remove bots and agents only after you've pulled their human co-authors out of the commit trailers. Removing bots first is the easy mistake, and it deletes real people.
Recovering the authors
Two routes give you the same thing: one row per human with a commit count.
- Clone and shortlog.
git shortlog -sneon the default branch lists every author name and email with a commit count. It ignores GitHub's 100 and 500 limits because it reads the history directly. - API with the anonymous flag. The REST "List repository contributors" endpoint includes anonymous contributors when you set
anonto 1 or true. Compare the counts with and without the flag. The gap is exactly what the default view was hiding.
Deduping is manual judgement. One person often commits under a work email and a personal email, or under a full name and a handle. Merge them when name and email clearly point to the same human, and keep them separate when you're unsure. A duplicate row costs a minute later. A wrong merge credits one person's work to someone else.
# 1. Every author on the default branch, with commit counts and emails git shortlog -sne HEAD # 2. REST contributors including anonymous authors (page until a page comes back empty) GET /repos/OWNER/REPO/contributors?anon=true&per_page=100&page=1 # 3. Commits carrying a Copilot coding agent session trailer git log --grep="Agent-Logs-Url" --format="%H %an <%ae>" # 4. Every co-author credited on each commit (parse BEFORE removing bots) git log --format="%H %an%n%(trailers:key=Co-authored-by,valueonly)" # 5. Bot-named authors to review before removal git shortlog -sne --author="\[bot\]" HEAD
Replace OWNER and REPO; run the git commands inside a fresh clone with the default branch checked out.
Removing bots and agents
These markers identify agent and bot work:
- Bot author names, such as
devin-ai-integration[bot]or any login ending in[bot]. - Agent branch prefixes, such as PRs from
head:copilot/. - The Agent-Logs-Url trailer, which Copilot coding agent commits now carry and which points to the session that produced them.
- Agent co-authorship lines. When a Copilot agent PR is squash-merged, GitHub credits
Co-authored-by: copilot-swe-agent[bot].
The volume is real. The AIDev dataset alone covers 7,685,281 pull requests across 961,168 repositories from six AI coding agents. Detection is a moving target, though: a new agent can ship a new trailer format. Check for current attribution trailers with a tool such as commit-check, and re-read GitHub's changelog when your counts look odd.
Rust example. The study doesn't report how many bot or agent rows it removed, and nobody has published how much bot removal shrinks a typical repo's contributor count. On your repo, log two numbers: rows removed, and humans re-credited from Co-authored-by lines. If the second number is zero on a repo that uses agents, your parsing is broken.
Where should the casual cut and the core cutoff go?
Set aside anyone with one commit or fewer. That's about half the people and under 2% of the commits. Then, optionally, mark as core the smallest group that together accounts for 80% of commits. On any project that squash-merges, re-run the casual cut by merged PRs before you discard anyone.
The published splits disagree because they count different units:
| Study | Group | Share of people | Share of work |
|---|---|---|---|
| Pinto 2016 | Casual (1 commit) | 48.98% | 1.73% of commits |
| SANER 2020 | Casual, counted by PRs | Not given | 12.5% of accepted contributions |
| Rust (ICSE 2024) | Core | 7.0% | 80% of commits |
| Rust | Paid devs within core | 20.2% | Not stated |
| npm | Company-affiliated users | 31% | 57% of PRs |
Sources: Pinto, Steinmacher and Gerosa (SANER 2016); the SANER 2020 replication; Zhang et al. (ICSE 2024); an npm affiliation study.
The size of the casual tail varies by ecosystem: 39% of contributors in C projects and 61% in JavaScript. Its share of commits stays small everywhere: 1.02% in linux, 3.46% in rails, 3.19% in django. And casual doesn't mean trivial. 28.64% of casual contributions are grammar and typo fixes, but 30.20% fix bugs. In company-owned projects, most external developers are casual contributors with a single contribution.
Wrong turn 2: cutting casual by commits alone. Counted by PRs, the casual group accounts for 12.5% of accepted contributions, against 1.73% counted by commits. That's roughly a sevenfold difference. A PR can hold many commits, and a squash merge collapses it into one, so a substantial contributor on a squash-merge project looks exactly like a typo fixer. Before you cut, check how the project merges. If it squashes, rank by merged PRs.
Rust example. About 1,300 one-time contributors go into a set-aside pile. They aren't deleted. The 2,313 peripheral contributors become a second-tier pool, and 2,180 of them are volunteers, which makes them interesting for junior roles. The 272 core developers carry forward. The study uses the commit-share cutoff, so if you rebuild this yourself, also run the merged-PR version and promote anyone whose PR count puts them well above the casual line.
How do you split out sponsor staff and off-limits employers?
Give every core row an employer status of sponsor, off-limits, unverified or clear, and require at least two of these signals to agree: org membership, email domain and profile company field. Expect the top of any commit-sorted list to be the sponsor's own engineers. That's how funded projects work, not an anomaly.
The evidence points one way:
- In company-owned projects, internal developers submit 43.3% of pull requests, and even with strong outside support, employees still hold the central roles.
- In Rust, paid developers are 20.2% of the core (55 people), against 4.8% of one-time and 5.8% of peripheral contributors.
- In npm, the 31% of users who disclose a company affiliation created almost 57% of pull requests.
Employers fund sustained work, and sustained work is what puts people in the core. So the people you most want are also the people most likely to be employed by the sponsor or by a company you've agreed not to recruit from.
A commit-sorted contributor list mostly tells you who the sponsor pays, not who you can hire.
Wrong turn 3: ranking by commit volume before the employer split. If you sort by commits and start at the top, you spend your first day researching people who are off-limits, and you may contact some of them before anyone notices. Do the employer split on the whole core before you rank anyone.
Each signal proves something different and fails in its own way:
- Org membership. Shows a current affiliation with the sponsor's GitHub organisation. It misleads when former staff haven't been removed, or when the person never made their membership visible.
- Email domain. A company domain on recent commits strongly suggests employment at the time of the commit. It misleads when someone keeps committing from an old employer address, or uses a personal address for everything.
- Profile company field. Free text the person typed. It's self-reported and often stale, so it never decides a row on its own.
- CODEOWNERS listing. Proves responsibility for a path, not who employs the person. Useful later for ownership, useless for employer status.
Nobody has published how often these signals agree with each other, so log your own disagreement rate. A row with only one signal gets "unverified" and stays off the slate until a second signal confirms it. Your off-limits list comes from your own agreements, not from the repo. Apply it here, in the same pass.
Rust example. The 55 paid core developers don't get cut automatically, because the study tags payment by any employer. They go into an employer-check pile, and only those employed by an off-limits company drop out. The 217 core volunteers are the clean pool.
Joining people to their employers is the slowest part of this step. Refolk handles it as part of the question: ask in plain English for a project's maintainers with the employer exclusion and the location included, and you get back people whose GitHub work and professional records have already been matched.
What proves subsystem ownership, and who has a permitted contact path?
Nobody has published thresholds for subsystem ownership, so the thresholds below are my own choice, and you should write yours into the log. Contact is stricter: use only an email or link the person has published themselves, never one taken from commit metadata.
Ownership: my thresholds, flagged as mine
I mark a person as a subsystem owner if any one of these holds:
- They are listed in CODEOWNERS or a MAINTAINERS file for a specific path.
- They reviewed at least 10 merged PRs touching that path. The number is my choice, sized so that one busy month doesn't qualify someone.
- The project names them in a release-manager role.
What each one proves: a CODEOWNERS or MAINTAINERS entry proves the project trusts them with a path. Review counts prove they are actually doing that work now. A release role proves they're trusted across the codebase. How each one misleads: ownership files go stale and keep people who left long ago, and review counts can be inflated by rubber-stamp approvals on trivial PRs. Check the date of the person's most recent review on that path before you mark them as an owner.
Contact: the rule
The terms also expect you to respond promptly to complaints, removal requests and "do not contact" requests. I couldn't confirm the current section numbers, so read the current GitHub Acceptable Use Policies before you run a campaign. Whether a public "open to opportunities" statement counts as clearance isn't established either way, so treat it as a signal of interest, not permission. For a fuller treatment of clearing repo-derived contacts, see the library's Repo-Derived Contact Clearance standard.
Finding a published channel means searching beyond GitHub: personal sites, talk pages, professional profiles. Refolk searches across GitHub, LinkedIn and the open web together, so a question like "reviewers on the PyTorch distributed module who have a public email or personal site" comes back already filtered to people with a self-published channel.
Which contributors make the slate
Rust example. The study has no ownership or contact data, so the path from 217 core volunteers (plus whoever clears the employer check among the 55) to a slate of 15-25 is yours to log. Rank the people in the top-right quadrant by ownership first, then by sustained contribution, then by fit to the role, and stop at 25.
How this goes wrong
Seven failure modes account for most bad contributor slates. Each one either inflates the list with people you can't hire or hollows it out by losing the people you want, and each has a check you can run in minutes.
- Treating the graph as the whole population. The tail beyond 100 disappears, along with every unlinked author. Check: compare the graph's 100 against the distinct authors in
git shortlog -sne. - Leaving out anon=true. Large repos silently lose everyone past the 500th linked email. Check: pull the contributor count with and without the flag. Any gap is people you would have missed.
- Deleting bot-authored commits outright. Copilot agent commits list the human as co-author, so deleting them erases real people's credit. Check: parse Co-authored-by lines before removing anything, and confirm the re-credited count isn't zero on a repo that uses agents.
- Defining casual by commits only. Under squash merge, one PR collapses into one commit, so substantial contributors look casual. The casual group's share of work is 1.73% by commits and 12.5% by PRs. Check: re-run the cut using merged PRs.
- Splitting employers by the profile company field only. The field is self-reported and often stale. Check: confirm against email domain and org membership. Their agreement rate is unpublished, so log yours.
- Trusting a "core contributor" headline. Founders and DAO roles inflate it. In Refolk's index, 8 of a 25-person sample hold founder, CEO, president or VP titles. Check: cross-check against the repo's commit history before the person reaches the slate.
- Emailing addresses taken from commit metadata. GitHub's terms bar unsolicited email and expect you to honour do-not-contact requests. Check: confirm the address is published on the person's profile or personal site, and log where you found it.
Failure modes 1, 2 and 3 hollow the list out. Failure modes 5 and 6 inflate it with people who are off-limits or not engineers. Failure mode 4 does both, discarding real contributors while making the remaining core look more exclusive than it is.
What headline searches can and cannot do, and how to keep the slate current
Headline keyword searches can't replace repo evidence, because most contributors never describe themselves as maintainers. Use them to confirm identity and find published contact paths for people the repo has already qualified. Then rebuild the cut log on a schedule, because the core of a project changes.
| Search in Refolk's index | Count | Ratio (derived) |
|---|---|---|
| "open source maintainer", US | 124 | Baseline |
| "open source maintainer", Germany | 47 | 0.38x the US figure |
| "core contributor", US | 600 | 4.8x the US maintainer figure |
| Leadership titles, 25-person "core contributor" sample | 8 | 32% |
Source: Refolk's index. The title breakdown comes from a 25-person sample, so treat the 32% as indicative, not precise.
Two things follow. First, the maintainer label is rare: across the whole United States, 124 people use it, so a headline search will miss most of the people your cut log finds. Second, the "core contributor" label is common but loose, inflated by founders and DAO roles. Run the repo cuts first, then use profile searches to resolve each qualified login to a person and a published channel, never the other way round.
Keeping it current
- Re-run the author recovery and core cut on a schedule. Quarterly works for an active project. Subsystem owners rotate, and a stale CODEOWNERS file will keep pointing at people who have moved on.
- Re-check agent markers. If a new coding agent appears in the history with its own trailer, add it to your filter and re-credit its human co-authors.
- Carry the do-not-contact log forward. A request made last quarter still applies, and it belongs on every future slate built from the same repo.
- Keep the cut log, not just the slate. When a hiring manager asks why someone is missing, the log answers in one line.
REPO: Displayed contributor count: Graph list size (max 100): Default-branch commits (insights off at 10,000+): Authors after anon=true or shortlog dedupe: Bots and agents removed: Humans re-credited from Co-authored-by: Casual set aside (<=1 commit): Re-checked by merged PRs? Y/N Core (80% of commits): Peripheral kept as tier 2: Sponsor employees split out: Off-limits employers split out: Unverified employer (one signal only): Subsystem owners (threshold used: ____________): Cleared contact path: Dropped, no path: Do-not-contact logged: Slate size: SLATE ROW Name | GitHub login | Subsystem or path | Ownership evidence | Employer status + two signals | Contact channel + where published | Rank
One block per repo. Every slate row must point back to a logged cut; leave nothing blank, write "not checked" instead.
Before you send the slate
- The cut log records the displayed count, the graph size, and the deduped author count from shortlog or anon=true.
- Bot and agent rows were removed only after Co-authored-by trailers were parsed and humans re-credited.
- The casual cut was re-run by merged PRs if the project squash-merges.
- Every slate member has an employer status confirmed by at least two signals, checked against the off-limits list.
- Every slate member is a subsystem owner or sustained contributor under a threshold written into the log.
- Every slate member's contact channel was published by them, and the log records where.
- No slate member appears on the do-not-contact log.
- The slate has 15 to 25 people, ranked, and each row traces back to a logged cut.
Questions practitioners ask
How do I get the full list of contributors to a GitHub repo, not just the top 100?
Clone the repo and run git shortlog -sne on the default branch, or page through the REST contributors endpoint with anon=true. The graph caps at 100 people, and the API links only the first 500 author emails to accounts. Anyone past that comes back anonymous, and only if you set the flag. Dedupe by name and email afterwards, because one person often commits under more than one address.
Should I exclude one-time contributors when sourcing from an open source project?
Set them aside, but don't delete them. In Pinto et al., people with at most one commit are 48.98% of contributors and write 1.73% of commits. Counted by pull requests, that share rises to 12.5%. On a project that squash-merges, one substantial PR shows up as one commit, so re-run the cut by merged PRs before you discard anyone. 30.20% of casual contributions are bug fixes, not typo fixes.
Can I email contributors at the address in their commits?
No. GitHub's terms, as reproduced in a court exhibit, say information gathered from GitHub must not be used to send unsolicited email to users. They also expect you to honour do-not-contact requests promptly. Use only an email or link the person has published on their profile or personal site. Read the current Acceptable Use Policies yourself, because I could not confirm the current section numbers.
How do I tell which contributors work for the company that sponsors the project?
Check at least two of three signals: membership in the sponsor's GitHub org, the email domain on their commits, and the profile company field. The company field is self-reported and often stale, so it can't decide a row on its own. Nobody has published how often these signals agree. If only one signal is available, mark the row unverified instead of guessing. Expect sponsor staff at the top of any commit-sorted list.
How do I filter bots and AI agents out of a contributor list?
Remove logins ending in [bot], commits from branches prefixed head:copilot/, commits carrying an Agent-Logs-Url trailer, and agent Co-authored-by lines. Before deleting anything, parse the Co-authored-by trailers. Copilot coding agent commits name Copilot as the author and the human who assigned the task as co-author, so filtering on author alone deletes the person who did the work.
Try it on the search you came here for
Stop building boolean strings. Just describe the person.
Type one sentence. I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web as it is right now, and hand back a ranked list with the reason next to every name.
01Describe them
One plain sentence. Role, city, stack, stage, whatever matters to you.
02I read the web live
GitHub, public LinkedIn and Crunchbase records, the open web. Not a database that went stale last quarter.
03You read the shortlist
Ranked, with the reasoning under every name. Open a profile, ask a follow-up, narrow it down.
- 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
- No boolean, no filters, no seat to buy. One box.
- Read at search time, so a profile updated yesterday counts today.
- Every step visible as it runs, every name with its reason.
500 free credits on sign-up. No card, no demo call. See real searches.