How to write a DSH plugin
Most published plugins are never used by anyone but their author. These are the reasons, and how to avoid them.
This directory indexes 715 DSH plugins. That number is a useful sample for one purpose: seeing what separates a plugin someone else installs from one that dies quietly at zero stars. 23 catalogued projects have never been starred at all, and roughly half sit below three stars. Almost none of that is because the code is bad.
What a plugin actually is
A DSH plugin is a package that the runtime discovers and registers at startup. The runtime does not know what your plugin does — it knows how to load it. Everything after that is your problem, which is both the freedom and the trap.
Minimum viable structure:
your-plugin/
├── package.json # name, main/exports, dsh metadata
├── index.js # entry point
└── README.md # the only documentation most users will read
Mistake 1: naming the package after the repository
The most common reason a plugin installs cleanly and never loads. Users register the name they cloned, your package exports a different name, and the mismatch fails silently.
Pick the package name first, make it short, and make the repository name match it. If your plugin needs a category hint, put it in the description, not in the package name — searched-for names are long, registerable names should not be.
Mistake 2: not shipping a build
If you write TypeScript, either commit the compiled output or make the build step
impossible to miss. A plugin whose main points at dist/index.js
with no dist/ in the repository fails to load on every machine except yours,
where you built it months ago and forgot.
Better: point main at source and let the runtime handle it, or use a
prepare script so npm install always produces a working tree.
Mistake 3: no README section that says what breaks
Users do not read your diff. They read the first screen of your README and then try something. The section that saves both of you time is the one nobody writes: known limitations. What does your plugin not handle? Which runtime versions does it require? What happens when the permission is denied?
A plugin that documents its own failure modes gets filed issues that are actionable. One that does not gets issues that say "doesn't work".
Mistake 4: silent early returns
If your plugin cannot do its job — permission denied, config missing, unsupported platform — throw or log. Returning early and doing nothing is how the ecosystem acquired its reputation for mysterious failures. Being loud in a failure path costs you nothing and saves every user an hour.
What the maintained plugins share
Looking at the projects in this directory that have kept their push dates current, four habits show up repeatedly:
- A screenshot or a GIF in the README. For anything with a visual surface, this is the difference between being tried and being scrolled past.
- One-line install. If installation needs a paragraph, it needs a simplification, not a paragraph.
- Small scope. The plugins that survive do one thing. The ones that try to be a framework get abandoned when the author runs out of weekends.
- Version-pinned compatibility note. "Requires DSH ≥ x.y" in the README prevents most of the "doesn't work" issues before they are filed.
Publishing checklist
- Package name is short, unambiguous, and matches what users will type
- Registering it produces a visible effect you can verify in one command
- Build output committed or generated by
prepare - README answers: what it does, how to install, what it requires, what it breaks
- Failure paths throw or log — never return silently
- Last push date is visible, because users will judge you on it
Getting listed
Submission is open and free — see submit a plugin. Listings are generated from public repository metadata, so a clear description matters more than a submission form: the category you end up in is inferred from your description.
If you want to see what a well-presented plugin looks like next to its neighbours, browse the categories. The contrast between a project with a real README and one with three lines of text is visible on every page.