Singh Labs ← all notes

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:

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.