dsh-plugin-shop
The plugin shop for DeepSeek Harness — browse a catalog of
dsh plugins, install one with a single confirmation, and manage what you have, from a tab inside Settings.
English | 中文
📦 Install
Two tracks below. They do the same thing; pick the one that matches who is reading.
🧑 For people
Prerequisites: Node.js. Running the harness itself needs no install — the
upstream-documented form is npx -y @deepseek-ai/dsh web. Plugin management
goes through dsh plugin, which spawns both the dsh command and pnpm —
install them once with npm install -g @deepseek-ai/dsh pnpm and verify with
dsh --version and pnpm --version.
# dsh on PATH (global install). The explicit version pin matters: pnpm 11
# holds back very recent releases, so a bare `add dsh-plugin-shop` can hand
# you an older version for a while. Pin the current release — refresh it
# with `npm view dsh-plugin-shop version`.
dsh plugin --profile web add dsh-plugin-shop@0.8.2
# or straight through npx, nothing installed:
npx -y @deepseek-ai/dsh plugin --profile web add dsh-plugin-shop@0.8.2
Replace web with your profile if you use another one. Then restart dsh once — a
newly added bundle is not applied to a running process — and open
Settings → Plugins → Plugin shop
You land on a shelf of plugin cards with a search box. The first load reads the catalog
over the network and can take a few seconds; a shimmering skeleton stands in until the
cards arrive.
🤖 For agents
Non-interactive, no prompts, nothing to confirm. --profile is mandatory —
without it dsh plugin exits with
error: required option '--profile <name>' not specified.
1. Resolve a profile name. Profiles are directories under $DSH_HOME/profiles
($DSH_HOME defaults to ~/.dsh). node_modules appears there too and is not a
profile.
ls -1 "${DSH_HOME:-$HOME/.dsh}/profiles" | grep -v '^node_modules$'
2. Install. Pin the version — the explicit pin bypasses pnpm's release
cooldown, and deterministic installs are the point of the agent path.
dsh plugin --profile <profile> add dsh-plugin-shop@0.8.2
3. Verify — do not skip this. A zero exit from step 2 means pnpm resolved the
package, not that the profile will load it. Assert on the bundle list:
dsh plugin --profile <profile> list --depth 0
dsh-plugin-shop must appear with a resolved version. If you would rather read the
manifest directly, the same fact lives at
$DSH_HOME/profiles/<profile>/package.json under dsh.profile.bundles.
4. Restart the profile — dsh --profile <profile>, or dsh web for the web
profile. Enabling or disabling an already installed plugin is hot; adding a new
bundle is not.
Failure modes
| What you see | What it means | What to do |
|---|
error: required option '--profile <name>' not specified | --profile was omitted | Pass it; there is no default |
A version older than npm's latest gets installed | pnpm 11 holds back very recently published versions | Pin the version explicitly: dsh plugin --profile <p> add dsh-plugin-shop@<version> |
client bundles not found ... lib/client.js | the copy on disk was built without its browser half | Install from npm rather than from a source checkout, or run pnpm build in that checkout |
dsh: pnpm not found on PATH — install pnpm to manage profile plugins | dsh plugin forwards to pnpm, and pnpm is missing | npm install -g pnpm |
no profile directory found above <path> | the plugin could not locate its profile | Please report it — this is resolved from ctx.baseUrl and should not fail |
| The tab is missing after a restart | the bundle is not in the profile's bundles | Re-run step 3; if it is absent, step 2 did not complete |
🖼️ Screenshots
✨ What it does
| |
|---|
| Browse & search | Thousands of plugins, harvested from the whole public npm registry by the dsh-plugin and deepseek-harness keywords and from GitHub repositories using them as topics — shown with the author's own summary when they declared one, and sorted into seven categories |
| Install | One confirmation. An unreviewed plugin requires an explicit acknowledgement first — an installed plugin holds the same privileges as a built-in one |
| Enable / disable | Applies to an installed plugin without a restart. A plugin with a browser half also needs the open page reloaded, and the shop offers the button when it does |
| Installed state | An installed plugin shows an Installed label on its card — or an Update button when the catalog has a newer version — plus an Uninstall button; the Installed filter in the category bar shows only installed plugins |
| Size & author | Each card shows what installing the plugin puts on disk, next to the account that published it — npm's own unpacked figure, so it matches the package's npm page |
| Leave out what cannot run | A plugin whose declared components your installation does not provide is badged incompatible; the filter at the end of the category bar takes those off the shelf. It never hides a plugin whose name is already taken by another install, and never subtracts from the Installed view — those cards are the only place the problem is explained or can be undone |
| Reload | When an uninstall or a toggle is already live on the server and only the open page is stale, the shop offers to reload that page — never automatically, because a reload discards work in flight |
| Restart | When the plugin's host half could not be brought up live — and also when it could, but the plugin has a browser half: a plugin that arrives mid-session reaches the page only through a restart, so the shop says so rather than offering a reload that would change nothing. It states the cost first: the page disconnects and in-flight work is interrupted |
| Self-update | The shop shows its own version next to the search box, checks npm for a newer release, and updates itself with the pinned version — then the usual restart |
🔎 Where the shelf comes from
The catalog is not a list anyone curates by hand. Six steps run every day, and two of
them are the reason the shelf is worth reading:
- Harvest the whole registry. Every npm package carrying
dsh-plugin or
deepseek-harness, plus every GitHub repository using them as topics. Nothing is
submitted; there is no queue.
- Gate every candidate. Most of what is harvested never reaches the shelf; the
live badges on the
repository README count both sides.
A package with no
dsh.bundle is a library, not a plugin. No
license or no repository means nothing can be audited. Deprecated on npm is out; a
repository listing additionally needs no build scripts and no workspace:
dependencies, either of which would fail the install on your machine. A name a hair
away from a popular one is held until someone clears it. Seventeen recorded
reasons, all mechanical, and every rejection carries a line its author can read.
- Classify and record. Seven categories, and the peer modules each plugin
declares — names only, never version ranges.
- Publish. Content-addressed JSON, to npm and GitHub Pages at once.
- Fetch here. This package races the origins and verifies the sha256 before
trusting a byte.
- Check dependencies here too. Your installation resolves each recorded peer name
against your profile — the same question dsh's loader asks at mount time. A card
whose modules are absent reads Incompatible and names them. That verdict is
computed on your machine, because it depends on the harness you are actually
running, not the one the build ran on.
The full pipeline diagram lives in the
repository README.
One thing this does not do: no listing has been read by a human. verified.yml is
empty today, every entry is community-tier, and every install asks you to acknowledge
that. Mechanical filtering is not review.
🧩 How it is put together
Two halves ship in this one package, and the split between them is the security
boundary:
| Half | Entry | Can reach | Cannot reach |
|---|
| Host | dsh-plugin-shop | The network (catalog fetch and sha256 verify), the filesystem (cache), dsh plugin add under a per-profile mutex | — |
| Client | dsh-plugin-shop/client | Exactly nine shop/* Remote methods | The network, the filesystem |
Compromising the browser half buys an attacker those nine calls and nothing more.
⚙️ Configuration
The shop reads its catalog from whichever source answers first: the npm
package dsh-plugin-shop-catalog (via your configured registry, npmmirror,
or npmjs) or https://LivXue.github.io/dsh-plugin-shop/v1/. All of them
carry the same bytes; the race exists because the link to one of them can be
far slower than the link to another. Setting DSH_SHOP_CATALOG_URL opts out
of the race and uses only what you name.
| Variable | Effect |
|---|
DSH_SHOP_CATALOG_URL | Read the catalog only from this base, instead of racing the default sources |
📚 The catalog
Built daily from the public npm registry and published as static JSON:
/v1/index.json — the pointer, carrying schemaVersion, builtAt, the entry count and rejected totals (the badges above read them live), and the content hash
/v1/plugins.<sha256>.json — the data, content-addressed and safe to cache indefinitely
The pointer is small enough to poll. The shop verifies the data file's sha256 against
the pointer before trusting a byte of it.
⚠️ What it does not claim
A listing is not an endorsement.
capabilities is whatever the author wrote about their own package. There is no
sandbox in v0, and the interface never renders that field as an enforced permission
list. The verified tier means a human read that exact version; a newer publish
downgrades it to verified-stale and keeps the review pinned to the version it was
actually given — so passing review once cannot buy trust for every future release.
🏷️ For plugin authors
Add a harvest keyword — "keywords": ["dsh-plugin"] or "keywords": ["deepseek-harness"] — to
package.json and publish. Or, without npm: add the keyword as a GitHub repo topic and keep a
package.json at the root with a name and dsh.bundle — the catalog lists the repo and pins the
default-branch commit as its version. The daily build finds you; nothing is submitted to this project. Declare a dsh.catalog section to control
your own category, summary and capabilities — or omit it, and the catalog derives a
listing from your npm description.
Full reference: docs/schema.md.
📄 License
Apache-2.0 © LivXue