One of the hardest parts of maintaining an open-source project is saying “no” to a good idea. A user proposes a new feature. It’s well-designed, useful, and has no obvious technical flaws. And yet, the answer is “no.” To the user, this can be baffling. To the maintainer, it’s a necessary act of stewardship.
Having created and maintained two highly successful open-source projects, Prefect and FastMCP, helped establish a third in Apache Airflow, and cut my OSS teeth contributing to Theano, I’ve learned that this stewardship is the real work. The ultimate success of a project isn’t measured by the number of features it has, but by the coherence of its vision and whether it finds resonance with its users. As Prefect’s CTO Chris White likes to point out, “People choose software when its abstractions meet their mental model.” Your job as an open-source maintainer is to first establish that mental model, then relentlessly build software that reflects it. A feature that is nominally useful but not spiritually aligned can be a threat just as much as an enhancement.
This threat can take many forms. The most obvious is a feature that’s wildly out of scope, like a request to add a GUI to a CLI tool — a valid idea that likely belongs in a separate project. More delicate is the feature that brilliantly solves one user’s niche problem but adds complexity and maintenance burden for everyone else. The most subtle, and perhaps most corrosive, is the API that’s simply “spelled” wrong for the project: the one that breaks established patterns and creates cognitive dissonance for future users. In many of the projects I’ve been fortunate to work on, both open- and closed-source, we obsess over this because a consistent developer experience is the foundation of a framework that feels intuitive and trustworthy.
So how does a maintainer defend this soul, especially as a project scales? It starts with documenting not just how the project works, but why. Clear developer guides and statements of purpose are your first line of defense. They articulate the project’s philosophy, setting expectations before a single line of code is written. This creates a powerful flywheel: the clearer a project is about why it exists, the more it attracts contributors who share that vision. Their contributions reinforce and refine that vision, which in turn justifies the project’s worldview. Process then becomes a tool for alignment, not bureaucracy. As a maintainer, you can play defense on the repo, confident that the burden of proof is on the pull request to demonstrate not just its own value, but its alignment with a well-understood philosophy.
This work has gotten exponentially harder in the age of LLMs. Historically, we could assume that since writing code is an expensive, high-effort activity, contributors would engage in discussion before doing the work, or at least seek some sign that time would not be wasted. Today, LLMs have inverted this. Code is now cheap, and we see it offered in lieu of discourse. A user shows up with a fully formed PR for a feature we’ve never discussed. It’s well-written, it “works,” but it was generated without any context for the framework’s philosophy. Its objective function was to satisfy a user’s request, not to uphold the project’s vision.
This isn’t to say all unsolicited contributions are unwelcome. There is nothing more delightful than the drive-by PR that lands, fully formed and perfectly aligned, fixing a bug or adding a small, thoughtful feature. We can’t discourage these contributors. But in the last year, the balance of presumption has shifted. The signal-to-noise ratio has degraded, and the unsolicited PR is now more likely to be a high-effort review of a low-effort contribution.
So what’s the playbook? In FastMCP, we recently tried to nudge this behavior by requiring an issue for every PR. In a perfect example of unintended consequences, we now get single-sentence issues opened a second before the PR! More powerful than this procedural requirement is a simple sentence that we are unconvinced that the framework should take on certain responsibilities for users. If a contributor wants to convince us, we all only benefit from that effort! But as I wrote earlier, the burden of proof is on the contributor, never the repo.
A more nuanced pushback against viable code is that as a maintainer, you may be uncomfortable or unwilling to maintain it indefinitely. I think this is often forgotten in fast-moving open-source projects: there is a significant transfer of responsibility when a PR is merged. If it introduces bugs, confusion, inconsistencies, or even invites further enhancements, it is usually the maintainer who is suddenly on the hook for it. In FastMCP, we’ve introduced and documented the contrib
module as one solution to this problem. This module contains useful functionality that may nonetheless not be appropriate for the core project, and is maintained exclusively by its author. No guarantee is made that it works with future versions of the project. In practice, many contrib modules might have better lives as standalone projects, but it’s a way to get the ball rolling in a more communal fashion.
One regret I have is that I observe a shift in my own behavior. In the early days of Prefect, we did our best to maintain a 15-minute SLA on our responses. Seven years ago, a user question reflected an amazing degree of engagement, and we wanted to respond in kind. Today, if I don’t see a basic attempt to engage, I find myself mirroring that low-effort behavior. Frankly, if I’m faced with a choice between a wall of LLM-generated text or a clear, direct question with an MRE, I’ll take the latter every time.
I know this describes a fundamentally artisanal, hand-made approach to open source that may seem strange in an age of vibe coding and YOLO commits. I’m no stranger to LLMs. Quite the opposite. I use them constantly in my own work and we even have an AI agent (hi Marvin!) that helps triage the FastMCP repo. But in my career, this thoughtful, deliberate stewardship has been the difference between utility projects and great ones. We used to call it “community” and I’d like to ensure it doesn’t disappear.
I think I need to be clear that nothing in this post should be construed as an invitation to be rude or to stonewall users. As an open-source maintainer, you should be ecstatic — in fact, you owe a significant debt — to every single person who engages with your project. After all, if you don’t want those interactions, keep your code to yourself! The goal in open-source must always be to create a positive, compounding community. Your responsibility is to ensure that today’s “no” helps guide a contributor toward tomorrow’s enthusiastic “yes!”
When this degree of thoughtfulness is well applied, it translates into a better experience for all users—into software whose abstractions meet a universal mental model. It’s a reminder that this kind of stewardship is worth fighting for.
Two weeks ago, I was in a room that reminded me this fight is being won at the highest level. I had the opportunity to join the MCP Committee for meetings in New York and saw a group skillfully navigating a version of this very problem. MCP is a young protocol, and its place in the AI stack has been accelerated more by excitement than its own maturity. As a result, it is under constant assault that it should simultaneously do more, do less, and everything in between.
A weak or rubber-stamp committee would be absolutely overwhelmed by this pressure, green-lighting any plausible feature to appease the loudest voices in this most-hyped corner of tech. And yet, over a couple of days, what I witnessed was the opposite. The most important thing I saw was a willingness to debate, and to hold every proposal up to a (usually) shared opinion of what the protocol is supposed to be. There was an overriding reverence for MCP’s teleological purpose: what it should do and, more critically, what it should not do. I especially admired David’s consistent drumbeat as he led the committee: “That’s a good idea. But is it part of the protocol’s responsibilities?”
Sticking to your guns like that is the hard, necessary work of maturing a technology with philosophical rigor. I left New York more confident than ever in the team and MCP itself, precisely because of how everyone worked not only to build the protocol, but to act as its thoughtful custodians. It was wonderful to see that stewardship up close, and I look forward to seeing it continue in open-source more broadly.
Subscribe
Comments
Reply to this post on Bluesky to join the conversation.
No comments yet...
🦗🦗🦗