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.
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. 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.
It’s a pessimistic outlook, I know. But when well appplied, this degree of thoughtfulness translates into a better experience for all users: into software whose abstractions meet the universal mental model. Two weeks ago, I was in a room that reminded me this kind of stewardship isn’t dead; it’s being practiced 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 whose place in the AI stack has been accelerated more by excitement than maturity. As a result, it is under constant assault with requests that it do more, be more, and solve everything in between.
And yet, over a couple of days, the most important thing I witnessed 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 its teleological purpose: what it should do and, more critically, what it should not do. I especially admired David’s consistent drumbeat: “This is a good idea. But is this what a protocol should do?”
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 the protocol, precisely because they understand that their job isn’t just to build a protocol, but to be its thoughtful custodians. It was a thrill 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...
🦗🦗🦗