I named three developer tools. All three names were taken on npm.
I shipped three small tools over about a week. Bridle, Interlock, Slopguard. I was pleased with the names — short, metaphors that explain the mechanism, not a vowel-dropped startup pun among them.
Then, quite late, I checked the npm registry.
$ for p in bridle interlock slopguard; do
curl -s -o /dev/null -w "%{http_code} $p\n" https://registry.npmjs.org/$p
done
200 bridle
200 interlock
200 slopguard
All three taken. Not squatted — real packages, by real people:
- bridle — "Javascript black magic RPC over websockets"
- interlock — interlockjs, a module bundler
- slopguard — "Don't let AI slop past your gate. Detect AI-generated code patterns"
That last one is doing roughly what mine does.
The actual bug this caused
Losing a name is annoying. That wasn't the problem.
The problem was already sitting in my README, in the install instructions:
npx github:manpreet171/bridle init # correct npx bridle lint # ...not correct
The first line is fine — explicit about the source. The second was copied from muscle memory, and it does something quite different.
npx github:user/repo fetches and runs from GitHub.
It does not install anything. So by the second command there
is no local bridle binary, and npx does what npx
does: goes to the public registry, finds the package literally named
bridle, downloads it, and runs it.
Six commands in that README would have run a stranger's websocket library on the machine of anyone following my own documentation.
Nobody was attacking me. I wrote the instructions myself, and they were wrong in a way that's invisible when you read them and obvious when you run them on a clean machine.
Why it's easy to miss
Because it works fine on your machine.
You've been developing the tool. You've got it linked, or installed globally,
or you're in the repo where node_modules/.bin has
it. npx bridle lint resolves locally and does
exactly what you expect.
It's only on a machine that has never seen your project that npx falls through to the registry. Which is every machine except yours.
The fix
Install explicitly from the repo, then use the short command:
npm install -g github:manpreet171/bridle bridle lint
Installing from a GitHub source skips the npm namespace entirely, so it doesn't matter who owns the bare name. Verify it links a real binary before you publish the instruction:
$ cd /tmp/check && npm init -y && npm install github:manpreet171/bridle added 1 package $ ls node_modules/.bin/ bridle bridle.cmd bridle.ps1 $ ./node_modules/.bin/bridle --version bridle — Harness Script Engineering CLI
That last line is the whole test. It's the binary I wrote, not the one someone else published under the same word.
What I'd do differently
Check the registry during naming, not after. It's one curl. I checked the domain and the GitHub org and skipped the one namespace my install instructions actually resolve against.
curl -s -o /dev/null -w "%{http_code}\n" https://registry.npmjs.org/<name>
404 is free. 200 means
somebody owns it and your README needs to be explicit forever.
Test install instructions on a machine that isn't yours. A clean container, or at minimum a temp directory outside the project. Docs that only work where the code already exists aren't docs.
Assume the good names are gone. Every short English noun that describes a mechanism is taken. Either accept a scoped or suffixed package name, or accept that you install from source and say so clearly.
I kept the names. They're good names and they're right for the tools. But the install line in all three READMEs now goes through the repo, and the pages on this site say plainly that the bare npm name belongs to someone else.
That felt like an admission when I wrote it. It's just accurate.
The tools: singhlabs.dev. All MIT, all zero-dependency, all installed from the repo rather than a bare npm name.
Anyone else been bitten by npx falling through to the registry? I suspect it's more common in READMEs than anyone realises, precisely because it never fails for the author. Tell me.