dsh plugin add: one command, one verification, one rollback
Installing a DeepSeek Harness bundle is three commands, but the middle one is the one everyone skips. dsh plugin add puts a bundle into a profile; dsh --dump-config proves it took effect; dsh plugin remove takes it back out. Run all three and “installed but not effective”—the most common failure state in this ecosystem—stops being a mystery and becomes a checkable line in the config tree.
This article walks the full lifecycle with a real bundle, dsh-modellix, so every command below is copy-pasteable. The same flow applies to any bundle. The dsh CLI itself is thin: per the official repository, it is “the sole supported Node application launcher”—profiles are ordered stacks of plugin-bundle patch layers, and dsh plugin manages them by forwarding arguments to pnpm in the profile directory.
The core command surface, as documented in the Modellix DeepSeek Harness docs and the official CLI readme:
| Command | What it does |
|---|---|
dsh --profile <name> |
Boot the named profile under $DSH_HOME/profiles/<name> |
dsh web |
Alias of --profile web |
dsh plugin --profile <name> <pnpm args> |
Manage a profile’s plugins by forwarding to pnpm |
dsh --profile <name> --dump-config |
Print the composed config tree without booting it |
dsh --profile <name> --dump-default-config |
Print the default template for comparison |
One disclosure before the commands: Modellix operates the plugin used as the worked example here, so we have a commercial interest in this flow working for you. Every command and quote below comes from our documentation or the official Harness repository, and versions are dated September 1, 2026.
This article is about the command flow. It is not about whether you need a plugin at all—that decision, including what a bundle is and when pure configuration is enough, lives in the DeepSeek Harness plugin guide. And if you only want to swap a model source, the custom provider path needs no plugin at all.
Before you run dsh plugin add: pinned versions and prerelease reality
Three version facts decide whether an install succeeds, and none of them are optional. The bundle you are installing was built and verified against specific versions of Harness and Node:
- DeepSeek Harness is pinned at
0.1.1-rc.2. The npm package@deepseek-ai/dshcurrently publishes0.1.1-rc.2aslatest(verified on the npm registry on September 1, 2026). There is a newer GitHub tag,0.1.2-alpha.1, but it has no npm release—treat0.1.1-rc.2as the current version. - Published-package runtime: Node.js
^22.19.0 || >=24.0.0. This is theenginesrange in the package manifest. - Source development and release verification: Node.js
24.18.1and pnpm11.24.0(from.nvmrcandpackageManager). If you build from source or verify a release, use these exact versions.
Why pinned? Harness is in developer preview. The official readme says it in full: “DeepSeek Harness is in developer preview and iterating rapidly. THERE WILL BE COMPATIBILITY-BREAKING CHANGES.“ The plugin’s readme adds the practical consequence: “Before upgrading Harness, check this package’s peer dependencies and CHANGELOG.” Every @deepseek-ai/dsh-* peer dependency is pinned to 0.1.1-rc.2, so a mismatched Harness is the most common silent cause of a bundle that installs but does nothing.
You also need the credential the bundle will use. For the worked example that is a valid Modellix API key—create it in the console at https://www.modellix.ai/console/api-key. One key covers the gateway and media endpoints the plugin’s modules route through; the live catalog the LLM module can reach is on the Modellix LLM page. Key storage itself is a separate topic covered in the DeepSeek Harness overview article. If you are new to the harness itself, that overview is the right starting point before any plugin work.
Install path 1: the published package (dsh plugin add dsh-modellix)
The simplest path installs the published npm package into the web profile:
1 | dsh plugin --profile web add dsh-modellix |
What happens: dsh plugin forwards add dsh-modellix to pnpm inside the profile directory, and pnpm resolves the package from the registry. The profile’s package.json automatically maintains the dsh.profile.bundles list in installation order, starting with @deepseek-ai/dsh-base.
The add command forwards to pnpm in the profile directory, which resolves the package and merges the bundle’s patch layer into the profile’s configuration tree.
Three things to get right:
- Name the profile explicitly.
--profile webtargets the web profile (the onedsh webuses). Install into a different profile—sdk,headless, or a custom one—and the bundle will not appear in the web UI. Replacewebwith your profile if you use a different one. - Do not start the web UI between add and verify. The install is not confirmed by a successful command exit; it is confirmed by the config tree, which is the next step. If you already have the profile running, restart it before verifying.
- The command forwards, it does not abstract. Anything you could do with pnpm in the profile directory—add, remove, install a tarball—goes through the same
dsh pluginforwarding layer. That is the whole design: one command, pnpm semantics underneath.
Verify with dsh –dump-config: the acceptance command
This is the step the third-party tutorials skip. dsh --profile web --dump-config prints the composed configuration tree—bundles, patches, and plugin rows—without booting the profile. It is the executable acceptance check for an install.
For the worked example, the acceptance criteria from the plugin’s own readme, verbatim:
--dump-configshould show thedsh-modellixBundle layer and a plugin row whose id ismodellix.
So you are looking for two things in the output:
- A Bundle layer named
dsh-modellixin the bundle list of the profile. - A plugin row whose
idismodellix—the bundle declares a plugin entry in itscordis.patch.yml(- insert: - id: modellix, name: dsh-modellix), and the composed tree materializes it as a row.
Reading the acceptance check: the composed config tree must show the dsh-modellix Bundle layer and a plugin row whose id is modellix.
If either piece is missing, the install did not take effect. Work the list in order:
- Did you restart the profile after installing? A plugin with a web client entry is a Client Bundle; reloading the browser alone does not load it. Restart the profile process, then re-run
--dump-config. - Is the version right? Harness must be
0.1.1-rc.2and Node inside^22.19.0 || >=24.0.0. A peer mismatch can leave the bundle registered but inert. - Did you install into the profile you are dumping?
--profile webin both commands must match. A bundle installed intosdkwill never show up inweb‘s tree. - Compare against the default.
dsh --profile web --dump-default-configprints the template a fresh profile starts from. Diffing the two outputs isolates exactly what your installs and patches contributed—which is also the fastest way to see what a laterremovewill take away.
This “verify the composed tree” habit is why the failure mode you read about most in the community—plugin logs present, behavior unchanged—is almost always one of the four items above. The command makes it diagnosable in ten seconds instead of a forum thread.
Install path 2: a local tarball from trusted source (pnpm pack)
When you want to install a bundle you can audit byte-for-byte, build a tarball from source yourself and add the artifact:
1 | pnpm install --frozen-lockfile |
The trust argument is the middle command. verify:release:static chains the static release gates: environment verification, type checking, lint, tests, build, verify:pack (which checks the exact artifact allowlist, bilingual documentation, and twelve locale-specific screenshots by actually decoding them), verify:fresh-install (installs the final tarball into a temporary project and smokes the entry points), and verify:node22-install (repeats the runtime smoke on a Node ^22.19.0 binary and fails instead of silently skipping when none is found). Installing the tarball pnpm pack produces is the same artifact that gate audited—which is the honest answer to “is it safe to install this plugin?”: you can verify the pipeline that produced the file before it ever touches your profile.
One limitation in the readme is worth quoting in full, because it stops a very common attempt:
Installing TypeScript source directly from Git requires the installation phase to produce
lib/. Until the package provides a verifiedprepareflow, use the published package or a local tarball.
In other words: you cannot dsh plugin add an unbuilt Git source directory. Cloning Modellix/dsh-modellix and pointing dsh plugin add at the checkout will not work until the installation phase produces lib/. Use the published package or a local tarball built as above. This is a general rule for bundles that ship TypeScript source without a verified prepare step—check the target package before assuming a directory add will build.
And after any install that replaces a previous local copy, restart the profile. From the readme: “Reloading the browser alone does not load a new Client Bundle.” The config tree is read at profile boot, not at browser refresh.
The trusted-source path: frozen install, static release verification, pack, then add the artifact—the same file the release gate audited.
The official publishing guide documents the underlying mechanics generically: the dsh.bundle.patch field in a package’s package.json marks an npm package as an installable bundle, and the same add / --dump-config loop applies to any of them.
Start the profile and confirm it loads
With the bundle verified in the tree, boot the profile:
1 | dsh --profile web |
Two first-run behaviors can look like failures and are not:
- A fresh profile may first show Harness’s own DeepSeek initialization dialog before the plugin presents its “Connect Modellix” dialog. Complete or handle the first one before the second appears.
- The plugin’s first-run dialog asks for the API key and confirms three default-on switches (Design, LLM, Web). “Configure later” is a real option, but it does not mark the plugin usable—the next explicit use of a capability that needs a credential will ask again.
One honest caveat: this article cannot promise “works after install.” Harness and this plugin use prerelease interfaces, and the versions above are the ones verified against each other as of September 1, 2026. If you are upgrading either side, re-check peer dependencies and the CHANGELOG before trusting a previously verified install.
Removing a bundle: dsh plugin remove, and what it does not clean up
Uninstall is the same three-command shape, inverted:
1 | dsh plugin --profile web remove dsh-modellix |
Run --dump-config again and confirm the dsh-modellix Bundle layer and the modellix plugin row are gone, then restart the profile. Removal is the mirror of install: the bundle leaves the profile’s dsh.profile.bundles list, and the composed tree stops materializing its plugin rows.
What removal does not do is worth quoting from the readme, because it is the difference between “uninstalled” and “clean”:
Uninstalling the plugin does not promise to remove external environment variables, upstream tasks, or every piece of persisted Harness data.
Concretely, for the worked example: if you supplied the key as a MODELLIX_API_KEY environment variable, that variable lives in your launch environment, not in the profile—remove it there. Credentials stored through the Harness Credential service are a separate store from modellix-cli‘s keychain; the plugin does not read a CLI login automatically, and removal does not purge the Credential store entry. Upstream tasks (billed media jobs already submitted) keep running to completion upstream regardless of plugin state. If your policy requires cleanup, handle each system separately. The official publishing guide linked above shows the same remove flow for any bundle.
dsh plugin registry: where bundles come from, and how to judge one
There is no official plugin marketplace. DeepSeek has not shipped one—community threads have explicitly asked for it, and the closest thing is the GitHub topic dsh-plugin, which the official readme suggests for discoverability. Everything else is third party: marketplaces like dshmarket.com or dsh-plugin.org, and community directories like awesome-dsh-plugins. They are discovery channels, not attestations.
Which makes the judgment checklist the real content of this section. Before you dsh plugin add something from a directory:
- Peer dependencies are pinned to the Harness version you run. A bundle that declares
@deepseek-ai/dsh-*@0.1.1-rc.2peers was built against the version the worked example uses. A bundle that does not pin peers is a compatibility risk, not a red flag—just verify it. - The package ships a release gate. Screenshot-decoding artifact checks, fresh-install smoke tests, a Node-22 runtime check that fails loudly: these are evidence the author treats release as a process, not a publish button.
- Stars are a measured fact, not a verdict. The worked example here has exactly 1 star and 0 forks, measured on August 29, 2026—it is a brand-new project, and this article is not claiming it is popular or battle-tested. Star counts in directories are snapshots; check the repository yourself and date what you cite.
- Download counts are unverified. npm download numbers for this ecosystem are not something we have verified, and neither should you trust a directory’s copy blindly.
- Prefer the audit path when it matters. The local-tarball flow in this article is the strongest form of trust: you verify the pipeline, not a listing.
If you are looking for a dsh plugin list style command: the CLI does not define one. dsh plugin forwards every argument after --profile <name> to pnpm, so the installed bundle list lives in the profile’s package.json (dsh.profile.bundles, in installation order starting with @deepseek-ai/dsh-base)—and the composed result of everything installed is exactly what dsh --profile web --dump-config prints. When in doubt, dump the tree. The plugin guide linked at the top covers the mechanism and the “do you need one” decision in depth if you want the background.
Frequently Asked Questions
How do I know a dsh plugin actually installed?
Run dsh --profile <name> --dump-config and look for the bundle’s layer in the profile’s bundle list plus a plugin row whose id matches the plugin’s declared name. For the worked example, the acceptance criteria are verbatim: “the dsh-modellix Bundle layer and a plugin row whose id is modellix.” A successful dsh plugin add exit code alone is not proof.
I ran dsh plugin add but the Web UI shows nothing new.
Restart the profile process. A bundle with a web client entry is a Client Bundle, and reloading the browser alone does not load it. Then re-run --dump-config to confirm the bundle layer is actually in the tree before looking at the UI.
Can I dsh plugin add a GitHub repository directly?
Not if it is unbuilt TypeScript source. “Installing TypeScript source directly from Git requires the installation phase to produce lib/. Until the package provides a verified prepare flow, use the published package or a local tarball.” Clone, verify, and pack a tarball instead.
Do I need to restart Harness after installing or removing a plugin?
Yes for the profile that owns the bundle. Configuration is composed at profile boot; --dump-config reflects what the next boot will load. A running profile keeps serving its old tree until restarted.
How do I remove a plugin completely?
Run dsh plugin --profile <name> remove <pkg>, re-run --dump-config to confirm the bundle layer and plugin rows are gone, then restart the profile. Then clean what removal does not: environment variables, upstream tasks, and persisted Harness data are separate systems and are not touched by the plugin.
Is it safe to install third-party dsh plugins?
There is no official marketplace, so “safe” is your judgment call. Check that peer dependencies are pinned to your Harness version, that the package ships a real release-verification gate, and that you can audit the source. For anything sensitive, use the local-tarball flow so you install exactly the artifact you verified.
What is the difference between –dump-config and –dump-default-config?--dump-config prints the composed tree for the named profile—what the next boot will actually load. --dump-default-config prints the default template a fresh profile starts from. Diffing them isolates exactly what your installs and patches contributed.
DeepSeek Harness Agent Docs
Read the official Modellix DeepSeek Harness integration page, covering plugin setup, the LLM gateway, and web providers.
View DocsOpen the Modellix Console
Log in to generate your Modellix API key and check live per-model pricing for the whole catalog.
LoginCommand syntax, pinned versions, and release information reflect public sources as of September 1, 2026 and change frequently—DeepSeek Harness is in developer preview and iterating rapidly. Validate versions against the official repository before relying on them. Modellix maintains the dsh-modellix plugin used as the worked example and has a commercial interest in it.