Every Issue Already Had a PR: Contributing to Open Source When Agents Got There First
The plan that didn't survive the first afternoon
I set out to do one useful open source contribution a day, with a coding agent doing the legwork and me approving every comment and pull request before it went out. The plan was the classic one: find a small, fresh bug in a project I use, fix it, send the PR.
By the end of the first afternoon I had a problem. Almost every small, fresh bug I found already had a fix waiting.
What I actually measured
So I stopped guessing and measured it. I took the 34 small, recent issues I had looked at across agent tooling (MCP SDKs and servers, an agent SDK), AWS projects and Python libraries, and checked when the first pull request was linked to each.

A third of them had a PR within an hour, and in 11 of those 12 the person who opened the issue also opened the PR, minutes apart. That is what a coding agent's workflow looks like from the outside: find the bug, write it up, open the fix, all in one go. Another 7 were claimed within a day. A third of all 34 had two or more competing PRs, and one had nine.
To be fair to the numbers: this is not a random sample. These are the small, recently filed issues I was looking at, which is exactly the slice agents go after. Older, larger issues in the same repos behave differently. But that slice is also where most "first contribution" advice sends people.
Two other things showed up along the way. One popular project had a hundred or more open PRs and nothing merged in five weeks, so being first there buys nothing. And one project from a large company had turned off outside PRs entirely: you write a plan in an issue and their own agents implement it.
Where the doors were still open
The contributions that did go somewhere had something in common. I wasn't racing anyone for them.

A bug I hit in my own tools. My blog's build prints
a Node deprecation warning about url.parse(). I traced it
to the theme, found that an earlier PR had fixed one of four call sites,
and finished the job. Nobody else was looking at it, because nobody else
was staring at my build log.
A fresh automated test failure. typeshed runs its test suite against the newest library releases every night and opens an issue when it breaks. One morning a gRPC package had added an RPC and the Python standard library had backported a method. Both halves needed a fix, and the bot issue is a starting gun most people don't hear.
A check the maintainer asked for. An AWS Labs repository that publishes Extended Support prices asked contributors to spot-check rates against the AWS Price List. I checked EKS in every region, not just one. The maintainer changed their monthly check to read every region and credited it in the release notes. ElastiCache matched exactly. The DocumentDB follow-up found a real gap: one instance family had prices but no vCPU counts, so its cost could not be computed.
A flake that hit my own PR. One of my PRs failed CI on a network error in a test that makes hundreds of live requests. Three of the four HTTP calls in that tool had no retry. That fix helps every future PR in the project, which is a better reason to send it than being first.
A root cause where the policy says ask first. Some projects want agreement before an outside PR for an enhancement. There, the useful contribution is a comment: a minimal repro on the current version, the exact line, the one-line fix, and an offer to send it.
What made a PR easy to review
Being uncontested gets you a look. It doesn't get you merged. Maintainers now see a lot of plausible-looking generated code, so the thing I tried to send with every change was proof.

The two that took longest were also the ones I trust most. For the
url.parse() change, I ran the old and new logic over 182
combinations of links and site URLs and explained every difference. Then
I built a real site on both branches and got byte-identical output
(apart from a sidebar color the theme randomizes on purpose). For the
retry change, I set the retry count to zero and watched the new tests
fail, because a test that passes either way proves nothing.
The house-style step sounds minor and isn't. typeshed has a specific way of handling a method that exists in some patch releases but not others: temporary allowlist entries with a "remove once this version is on GitHub Actions" note. Following that exactly is the difference between a PR a maintainer can merge and one they have to rewrite.
What I would tell someone starting now
- Read the issue's timeline before you read its code. Linked PRs show up there. Thirty seconds saves an afternoon.
- Check that the project still merges things. Look at the last few merged PRs, and at who wrote them.
- Read CONTRIBUTING, all of it. Several projects now say how they want AI-assisted contributions handled, and at least one doesn't take outside PRs at all.
- Start from your own friction. Warnings in your build, a failure in your CI, a tool that does something odd. That queue has no competition.
- When you can't be first, be useful. Running someone else's PR and reporting what you found is still a contribution, and maintainers need it more than another fix.
As I write this, none of the PRs has been reviewed yet, so I can't tell you which of these approaches gets merged. The pricing check already changed someone's project. I'll come back with the rest.