You Imported a Maintainer
"Don't reinvent the wheel" was never a principle. It was a price. Generation went to zero, the price moved, and the thing you were actually buying was never the code.
By Jason Waldrip 08:40 9 min read
You asked for a relative timestamp. Something that renders “3 hours ago” under a comment. The diff comes back in under a minute: correct, tested, handles the plural, and it added one line to package.json. A date library. Four hundred thousand weekly downloads, MIT licensed, last published in June. You look at it for about two seconds and approve it, because that is exactly what you would have done in 2019, and in 2019 you would have been right.
Six packages came with it. You didn’t read their names, and neither did the reviewer after you, and neither will anyone else for as long as that line stays in the file.
the rule that was really a price
“Don’t reinvent the wheel” was never a moral position. It was arithmetic. Writing a date formatter yourself cost you an afternoon, plus the two bugs you’d find in month three, plus the review, plus the tests. Typing npm install cost nine seconds. When one side of a trade is an afternoon and the other is nine seconds, you stop deliberating and start installing, and every person who told you to do that was giving you good advice at the time.
March 2016 is the cleanest illustration anyone has. Azer Koçulu pulled more than 250 of his modules off npm after a trademark fight over a package name. One of them, left-pad, was eleven lines long and padded the left side of a string. It had been downloaded roughly 2.5 million times the month before. Its removal broke builds at Node, at Babel, and across thousands of projects, and npm’s CTO eventually force-restored the version to stop the bleeding.
That story usually gets told as a story about unpublish policy. Read it again with the price in mind. Thousands of teams had taken a dependency on eleven lines of code that any engineer on any of those teams could have written between two meetings. They weren’t lazy. In 2016, those eleven lines really did cost more than the install once you counted the test, the edge case, and somebody’s review comment about Unicode.
the price moved and the habit didn’t
Those eleven lines now cost a sentence. So do the four hundred lines of a competent date formatter, in your codebase’s style, with the tests, in about the time it takes to read this paragraph.
I’ve written about what else broke when generation went to zero: the fleet adds paths and never removes them, and the ratio nobody was watching quietly went sideways. This is that same asymmetry pointed at your dependency tree. One side of the build-versus-install trade collapsed to nothing. The other side didn’t move at all, and it was never really about typing anyway.
The fleet is the last thing that will notice. An agent trained on a decade of package.json files reaches for a package because that’s what a decade of package.json files did. Ask it to solve the problem and it will solve the problem the way the corpus solved the problem, correctly, in one minute, with a new name in your manifest. It has no opinion about how many names should be in there.
what you were actually buying
You never bought the code. The code was always sitting right there in node_modules where you could read it, and mostly you didn’t, and mostly that was fine.
What you bought was somebody else’s ongoing attention. Their bug fixes, their edge cases, their CVE patches at midnight, their willingness to keep caring about your problem after you stopped thinking about it. That’s a genuine product, and for most of what’s in your tree it’s worth far more than the zero dollars you paid for it.
It also comes attached to a person. The person is the part nobody prices.
In March 2024, Andres Freund noticed his SSH logins on Debian sid felt slow. He’s a Postgres developer, not a security researcher, and he was benchmarking something unrelated. His post to oss-security opens with about as mundane a sentence as a disaster has ever had: “After observing a few odd symptoms around liblzma (part of the xz package) on Debian sid installations over the last weeks (logins with ssh taking a lot of CPU, valgrind errors).” Half a second of extra login time. He pulled the thread and found a backdoor sitting in a compression library, reaching into sshd on its way to the world’s servers.
Here’s the part worth holding onto. That backdoor did not get in through a vulnerability. There was nothing to scan for, no unsafe function, no missing bounds check, because the code did precisely what its author intended. Somebody spent roughly two years being a helpful contributor to a library that one burned-out volunteer had been carrying alone, earned co-maintainer status the honest way, and then used it. The attack surface was a relationship.
Eighteen months later it happened again, faster and dumber. On September 8, 2025, a maintainer behind chalk and debug got a phishing mail from a lookalike npm domain. Inside about sixteen minutes of taking the account, the attacker had published malicious versions of eighteen packages that together pull something like two billion downloads a week. The payload hooked browser wallet APIs and tried to reroute crypto transactions. Reported takings came to a few hundred dollars, because it was caught within hours and because that’s all the attacker built it to do.
Sit with that ratio for a second. The ceiling on that afternoon was somebody’s ambition, not their permissions.
count maintainers, not packages
So here’s the shift I’d make in how you look at your own tree.
Every dependency is a standing grant of publish access into your build, issued to a person you have never met, renewed automatically every time you install, and revocable only by you noticing. Your lockfile pins a version, which is a seatbelt worth wearing and not the same thing as revoking the grant, because the next upgrade is the next opportunity and upgrades are not optional forever.
The interesting number isn’t how many packages you have. It’s how many humans can put code on your production servers without asking you. Nobody I know can say that number out loud about their own system. Most people have never seen it, and the transitive tree is where it actually lives, four levels down under something you chose for good reasons in 2021.
Now put a fleet on top of it. Agents open dependency bumps, add packages, refactor toward whatever library the corpus prefers, and every one of those PRs is defensible on its own the way every added code path was defensible on its own. An audit that was already too large for one person to hold is now growing at machine speed, and it grows in the one file everybody scrolls past.
the dependencies that got more valuable, not less
None of this is an argument for vendoring everything or writing your own crypto. The flip is asymmetric, and getting the two ends right is the whole judgment call.
At the small end, where the package is under a hundred lines and does one stable thing that hasn’t changed since 2014, the maintenance you’re buying is close to nothing and the grant is the same size as any other. Write it. You couldn’t afford to before. You can now.
At the big end, the maintenance is the entire product. When I chose Elixir for the GigSmart backend, I took on the largest dependency available to anyone: a full runtime, OTP, and decades of supervision-tree design that I was never going to reproduce and shouldn’t have tried to. That was never code I declined to write. It’s a body of operational knowledge with a compiler attached. A fleet can reimplement the surface of something like that in a weekend and will leave every war story out, because the war stories aren’t in the source. Same argument for Postgres, for the type checker, for the framework your team already knows at 2am.
Take the dependency when what you want is the maintenance. Write the code when what you want is the code. Almost everything that goes wrong here is one of those two mistaken for the other.
- Get the maintainer count. Not the package count, which flatters you, but the number of distinct publishing identities in your transitive tree. This is exactly the kind of tedious graph-walking a fleet is excellent at, so have it produce the list. Then read the list yourself, because the surprise is always in row forty.
- Make a new dependency argue in the PR. Every added package states what maintenance it buys, what it pulls in behind it, and what writing it instead would cost. An agent can draft all three honestly. The call about whether the trade is good is yours, and it takes thirty seconds once the evidence is in front of you.
- Separate install time from run time. A package has to execute to do its job. It does not have to execute during installation, on a developer laptop with an SSH agent and a cloud token in the environment. Lifecycle scripts off by default is the single cheapest thing on this list, and the September attack ran in exactly that window.
- Regenerate the small stuff deliberately. When the fleet reaches for a package to do something small and stable, ask for the function instead and keep it. You own it now, which used to be the objection and is now roughly the point.
So go back to that diff. It’s still open, it still says “3 hours ago” under the comment, and it works. Somewhere under that one line are six more names, and behind those names are people, and the whole thing is fine right up until one of them has a bad Tuesday with their email. How many of those people are there in your system right now, and when did you last look, and has that number been going up or down since the fleet started opening the pull requests?
Jason Waldrip is a fractional CTO and CAIO through The Bushido Collective, working with founders drowning in AI-generated code and teams scaling past the leadership that got them here. If nobody on your team can say how many people can publish into your build, that’s a good place to start a conversation. Work with me.
Written with AI assistance; the frame and the calls on what matters are mine. The xz details come from Andres Freund’s own oss-security post rather than a retelling.