Kurt McKee

lessons learned in production


Revitalizing stalled open source projects

Posted 24 August 2023 in open source and oss

I recently encountered an open source project that hadn't received updates for a while. The issue tracker had ~200 open issues, ~70 open pull requests, and CI was partially failing. It's not uncommon for projects to go through lulls, and that's where this project was at.

As is often the case, some person had posted an issue to ask "Is this project still maintained?" The person ended with this line:

If there's any way I can help, please let me know.

This post is a response to this very common refrain. It provides strategies for contributing to an open source project whose development has stalled by triaging pull requests and issues.

I'm writing this post as someone who has been on both sides of this over the last ~20 years of contributing to, and maintaining, open source software projects. I've encountered stalled projects and helped revitalize them, and -- as the long-time maintainer of a popular project -- I've benefited from others injecting energy into a project.

What is "triage"?

In this post, which is focused heavily on injecting energy into a stalled project, I'm using the word "triage" to mean "recommend to merge or close a PR, or to close an issue".

The suggestions in this post are written with several desired outcomes in mind.

  1. You want to get the maintainers' attention. A tidy batch of notifications might accomplish that.
  2. You want the maintainers to take an action. If they don't, the project will remain stalled.
  3. You want the maintainers to feel a rush of endorphins. Closing a batch of issues, or merging a batch of PRs, in five minutes might accomplish that.

These suggestions may not apply to active projects, which may have triage policies, but for a stalled project these suggestions may be just what the doctor ordered.

Be kind and be gracious

Be kind and be gracious to all the people you encounter. This is priority #1.

Remember that you're representing not just yourself but also the project, because some people will believe that you are affiliated with the project (and you may be asked to officially join the project based on your efforts!)

Authors and maintainers

The authors and maintainers will never, ever get back any time they spend on this project, so everything you do and say has to persuade them to invest their time in the project today and tomorrow. This is true whether they are constantly involved in the project or are absent for a long time.

Be kind when @-mentioning maintainers or referring to them during triage.

PR authors

PR authors may not be experts in any of the ways you're accustomed to or would prefer.

They may not be an expert in the given programming language, nor be familiar with the version control system or hosting site, nor be knowledgeable how to set up a testing environment, nor natively speak your language.

The project needs contributors to move forward, including the ones that submit less-than-ideal PRs, because they are investing their time to try improving the project.

Issue reporters

Everyone who reports an issue is doing so because they want something from the project. That's true whether they're reporting a bug, asking a question, or requesting a feature. The project needs the reports and questions and ideas to grow and evolve, so be gracious.

Find actors and doers

Here are some tips for finding the right humans to @-mention in your triage messages.

Find repository and organization owners

If the repo is owned by a single user, add that user to your list.

If the repository is part of an organization, check the organization's list of people and add organization owners to your list.

Find active humans

Just because the project is stalled doesn't mean its maintainers are inactive. For repos in organizations, review each org member's profile. People with activity charts like this should go on the list:

A GitHub activity chart showing consistent activity throughout the year.

People with activity charts like this are less likely to return:

A GitHub activity chart showing zero activity for an entire year.

Review recently-closed issues and PRs

Sometimes maintainers in organizations choose to remain private in the list of people, but you may find them by searching recently-closed issues and PRs.

You can use the following in the GitHub filter box for PRs to find the PRs most recently updated:

is:closed sort:updated-desc is:pr

You can use this in the filter box for issues:

is:closed sort:updated-desc is:issue

Look through the recently-closed issues and PRs and add the most recent closers to your list.

Cast an effective net

Once you have a list of people, divide it into groups of two or three users. When performing triage, limit the number of people you @-mention.

There are two reasons for this advice:

  1. Your triage message needs to be front-and-center.
  2. You want someone to take an action.

In the stalled project above I saw a PR where someone @-mentioned ~15 different people. Their actual request wrapped to a second line and everyone ignored the request, presumably because they were busy and thought someone else would respond.

Make a decision

Your goal during triage is to give the maintainers a 10-second path to a decision.

Orient yourself

It is wise to orient yourself by glancing through recent PRs and open issues. The purpose is to understand what has already been reported and submitted. It's possible several people have reported the same issue, in which case you can pick one and report the others as duplicates. People may have included the same fix in multiple PRs, in which case you can pick the smallest one to recommend for merging and then recommend closure for the rest.

After that orientation period, though, start triaging.

Accept that you'll make mistakes

You're going to make mistakes. It's fine!

I once encountered a feature request that seemed clearly out-of-scope for the project. I recommended closure, and a maintainer corrected me the next day that it was a great idea. (In fact, almost all of my suggestions were rejected, which simply demonstrated I wasn't in sync with the maintainers. It's fine!)

When your feedback doesn't match what the maintainers want, don't take it personally. You're trying to help, and you're being gracious and kind (AREN'T YOU?). Just keep doing that and you'll be fine.

If you click on it, triage it

Don't delay triaging something until later. Triage it when you click on it.

I can tell you from personal experience as a maintainer that it can be overwhelming to see a wall of pull requests or open issues. I worry whether I'm making the right decision, and then I realize that I don't have time right now to do things perfectly, so I may skip the thing with the best of intentions to come back to it later when I do have time for perfection.

As a non-maintainer, strangely, I don't feel that way, so my strong advice to you is: take advantage of the freedom you have as a non-maintainer, and make a decision. Try to make the right decision, but make a decision.

Be succinct

Challenge yourself to only write one sentence of explanation.

"10 seconds to action" includes the time it takes to read your triage message.

Pace yourself

Start small. Triage some limited number of issues or pull requests -- like 5 or 10 -- and wait to see if anything happens.

If a maintainer shows up and responds, then continue triaging. If nothing happens, you haven't wasted your own time by burning through the entire backlog of issues and/or PRs.

Make "close" your default response

Saying "no" is an extremely important skill, and recommending that an issue or PR be closed is the triage equivalent of a "no".

In the specific case that a project has stalled, I recommend making "no" your default response. If maintainers aren't investing time in the project, they're not going to spend time to implement a new feature nor review a PR.

In this section I'll suggest criteria that I've used to justify my closure recommendations.

Old feature requests

This criterion is easy to justify because you just have to cite a number.

@maintainer Please close this issue. It's 10 years old and is unlikely to be implemented.

Duplicate bug reports

When an issue has been reported multiple times, pick one and report the others as duplicates. (Never worry which one was posted first. Pick the "best" one, even if it was reported later.)

@maintainer Please close this issue. It's a duplicate of #1234.

Recent "How do I..." questions

Answer the question and recommend closing the issue.

If the user wants to ask follow-up questions, they're free to do so on a closed issue.

@user This can be accomplished using the [link to cool feature documentation].

@maintainer Please close this issue. I think it has been answered.

Huge PRs

Huge PRs cannot be reviewed effectively. I can't tell you what "huge" is, but you'll know it when you see it.

For the project that prompted this post, I saw a "bugfix" PR that changed ~2,500 lines across ~50 commits. I immediately recommended closure, and you should too.

@maintainer Please close this PR. It's too big to review effectively.

Reformatting PRs

It's objectively awesome when a project uses a code reformatting tool to standardize code.

However, it's objectively terrible to merge a reformatting PR into a stalled project because it is almost guaranteed to create merge conflicts for all other PRs.

Always recommend closure for reformatting PRs. They're trivial to create, and they usually ruin higher-value PRs.

@maintainer Please close this PR. It reformats the code and may introduce merge conflicts for other open PRs.

Look for merge opportunities

If a maintainer shows up and begins accepting your suggestions, closing issues and PRs is an easy way to feel good because numbers start counting down. However, it's also valuable to signal to others that the project has started moving forward, and my signaling strategy is simple: merge PRs. GitHub highlights when code was last merged at the top of every repository, so look for PRs that can update that message from "2 years ago" to "2 seconds ago"!

Below, I describe some of my selection strategies for identifying high-value PRs.

CI fixes

If CI is failing for reasons you understand, and a PR will fix the failure, recommend merging it.

Such PRs are especially high-value, because it helps evaluate all other PRs moving forward.

@maintainer Please merge this PR. It fixes an existing failure in CI.

Documentation fixes

Typo and formatting fixes are fairly common, and are typically easy to evaluate. Recommend merging.

@maintainer Please merge this PR. It fixes existing typos in the documentation.

Bug fixes

If the PR fixes a bug, and it is small and targeted, and it has unit tests then recommend merging.

The project might not have a requirement that PRs include tests, but you can, and you should, because the project needs to become more maintainable over time. Bug fixes without unit tests are not high-value. They represent a risk.

Remember: your goal is to make the maintainers feel good that things are going well, so they come back tomorrow and keep the project moving forward. If the software breaks because a bug fix wasn't tested, they're not going to feel good.

@maintainer Please merge this PR. It fixes a bug reported in issue #1234.

Expect everything, prepare for nothing

When a project has stalled, it's entirely possible that the maintainers will remain silent. Make sure you're prepared for that possibility, and don't take it personally if that happens.

Remember to limit your initial efforts, so you're not over-invested nor burned out.

Remember to be gracious, so you're representing yourself well.

Remember to have fun!

☕ Like my work? I accept tips!