20 merged PRs, not one of them a feature
How I actually got into open source, including 7 in the Hugging Face ecosystem, by fixing things that annoyed me.
I have 20 merged pull requests across 13 open-source libraries, 7 of them in the Hugging Face ecosystem. Not one of them is a feature. Every single one is a papercut, and that is the entire point.
The advice people give about breaking into open source is usually some version of "find an issue labelled good first issue and pick it up." I tried that. Those issues are either claimed within an hour or they are labelled that way optimistically and are in fact a three-week refactor.
What actually worked was much less romantic: I stopped looking for issues and started noticing when a library annoyed me.
20
Merged PRs
across 13 libraries
7
In Hugging Face
hub, transformers, accelerate
0
Features shipped
not one
What a real first PR looks like
Here is a genuine merged one, in huggingface_hub:
Fix misleading max_retries docstring in http_backoffThat is it. The docstring described the retry count in a way that did not match what the function actually did. I read it, got confused, read the implementation, discovered the docstring was wrong, and changed the docstring.
Total time: about twenty minutes. It is merged into a library that ships on millions of machines.
The confusion-to-PR pipeline
Nearly all 20 came out of the same loop. I was using a library for something unrelated, hit a moment of "wait, what?", and instead of working around it, spent fifteen minutes finding out why.
- The docs lie. A docstring says int, the code accepts int or float. Fix the docs.
xarray #11425was an incorrect parameter name in thecumulative()docstrings. - The error message is wrong.
transformers #47089was AqlmConfig telling users a value should be a float when it should be an int. Somebody would have burned an hour on that. - An edge case crashes.
transformers #47072,get_json_schemacrashed on a non-string docstring choice.matplotlib #32058,hsv_to_rgbcrashed on integer NumPy input. - Behaviour is inconsistent across siblings.
networkx #8728, boruvka used a different default than kruskal and prim for the same argument.
The one that taught me the most
huggingface_hub #4435: making filter_repo_objects pattern matching case-sensitive on all platforms.
That is a cross-platform bug. The behaviour differed depending on the filesystem underneath, which means it worked on the maintainers' machines and did not work on somebody else's. Those bugs are valuable precisely because the people best equipped to fix them are the least likely to encounter them.
If you develop on Windows, or on a case-insensitive filesystem, or in a locale that is not en_US, you have a genuine advantage. You will trip over things the core team physically cannot.
My actual checklist
- Read CONTRIBUTING first, all of it. Most rejected PRs from newcomers are rejected on process, not substance. Wrong branch, missing changelog entry, unsigned commit.
- One change per PR. A docstring fix bundled with a refactor becomes a discussion. A docstring fix alone becomes a merge.
- Write the PR body for a tired reviewer. What was wrong, what you changed, how to see it. Three sentences. They are reviewing this on a Sunday.
- Add the test if the project has tests for that area. A bug fix with a regression test is much harder to say no to.
- Then let it go. Some sat for weeks. One got closed and reopened. Chasing maintainers is the fastest way to become somebody they dread hearing from.
Why bother
The honest answer is that it is the only way I know to read production code written by people much better than me, with a real reason to understand it properly. You cannot skim when you are about to propose a change. You have to actually know what the function does.
The merged PR is a nice souvenir. The reading is the part that changed how I write code.