Skip to content

Plugin markets ​

Summary ​

A plugin market is one JSON index file that lists installable DSH bundles with their titles, icons, authors, and versions. Turn on the experimental Custom plugin markets bundle to browse markets in a Discover tab on the Plugins page and install a listed version after a confirmation. To publish a market, write or generate an index file and serve it, together with its icon files, from any static host.

Table of Contents ​

Turn on Discover ​

Open Plugins, select More beside Experimental plugins, find Custom plugin markets, and switch it on. A Discover tab appears next to Installed, and Creator mode gains the read-only plugin_market tool. Switching the bundle off removes both again.

DSH ships no index source. Select Discover, choose Add index source, and enter the URL of an index file. A URL must use http: or https: and must not contain a user name, password, or # fragment. Anyone on the network path can change an http: index, including the install specs it lists, so use https: for a market reached over a network you do not control. Each source belongs to the current profile.

Browse and install ​

The market menu at the left of the toolbar switches between sources and opens Manage index sources…, where each source shows its last error. Search matches names, authors, keywords, and titles, descriptions, categories, and labels in every language, and tolerates typos; results come in best-match order until you choose another. The Labels menu, category pills, and Sort menu use the categories, labels, and sort keys that the market declares, and Publish date sorts by each plugin's latest version.

Each card shows the plugin's recommended version: the highest version compatible with the running DSH that is not a prerelease, or the highest compatible prerelease when the plugin lists no version without a prerelease tag. Install opens a confirmation with that version's source: the npm package and registry, or the Git repository, commit, and directory. Confirming starts the normal plugin installation, including its compatibility and registry checks; nothing is installed without that confirmation.

Select a card to open its page. The Versions list shows every listed version with its compatibility and offers Install for any version DSH accepts, including older releases and prereleases. A card that shows Installed, Update available, or Provided by DSH opens the installed bundle instead.

Markets are third-party content. A market chooses each plugin's title, description, icon, author, and source; DSH checks the file format but not those claims. Add only sources you trust, and check the source in the confirmation before installing.

Publish an index ​

An index is a UTF-8 JSON file, at most 128 MiB by default, served with a 2xx status and without redirects. Put it on any static host, for example GitLab Pages, GitHub Pages, or an object store behind https.

Icons can be inline or separate files. An inline icon is a base64 data: URL in the index; it needs no extra request but makes the index larger. A separate icon is a URL. A relative icon resolves against the index URL, the way an image in a web page resolves against the page: for an index at https://market.example/dsh/index.json, "icon": "icons/foo.svg" loads https://market.example/dsh/icons/foo.svg. Publishing the index and an icons/ directory side by side therefore works on any host without editing the file. An absolute icon URL on another origin (scheme, host, and port) must use https:.

This is a minimal index with one npm plugin and one plugin from a Git monorepo:

json
{
  "format": 1,
  "title": { "en": "Team plugins", "zh": "团队插件" },
  "plugins": [
    {
      "name": "dsh-plugin-foo",
      "title": "Foo",
      "description": "Adds the foo tool",
      "icon": "icons/foo.svg",
      "author": "Jane Doe",
      "homepage": "https://github.com/jane/dsh-plugin-foo#readme",
      "repository": { "url": "https://github.com/jane/dsh-plugin-foo" },
      "versions": [
        { "version": "1.1.0", "publishTimestamp": 1790476800, "source": { "type": "npm" }, "engines": { "dsh": ">=0.2.0-rc.2" } },
        { "version": "1.0.0", "publishTimestamp": 1788000000, "source": { "type": "npm" } }
      ]
    },
    {
      "name": "@team/dsh-bar",
      "versions": [
        {
          "version": "0.3.0",
          "publishTimestamp": 1789000000,
          "source": {
            "type": "git",
            "url": "https://gitlab.example.com/team/dsh-plugins",
            "commit": "3f9c2e1d8a4b6c0e7f1a2b3c4d5e6f708192a3b4",
            "path": "packages/bar"
          }
        }
      ]
    }
  ]
}

DSH rejects the whole index when any rule below is violated and shows the reason, with the JSON path of the offending value, under the source in Manage index sources….

Generate an index with the reference generator ​

The repository includes a reference generator that builds an index from a plain list. Write one npm package name or https Git repository URL per line; blank lines and lines starting with # are ignored:

text
@team/dsh-foo
https://gitlab.example.com/team/dsh-plugins

Run it from a DSH checkout:

sh
pnpm --filter @deepseek-ai/dsh-plugin-market-generator start --input plugins.txt --output site/index.json --title "Team plugins"

For an npm package, the index lists every version that is not deprecated and declares dsh.bundle. For a Git repository, it finds the bundle packages on the default branch and lists their versions at vX.Y.Z, X.Y.Z, and <name>@X.Y.Z tags, plus each package's version on the default branch. Titles, descriptions, icons, authors, and homepages come from each plugin's highest version. Paths are relative to the directory where you run pnpm.

The generator only downloads and reads files; it never installs packages or runs their code. It keeps a cache in .plugin-market-cache next to the list, so a repeated run downloads only new versions and commits. Publish the output directory, index.json together with its icons/ directory, as described above.

Index format reference ​

Text fields marked LocalizedText are a string or an object of strings keyed by lowercase language ids, such as { "en": "Foo", "zh": "甲" }; an object must contain en. Members DSH does not know are ignored.

Index fieldRequiredMeaning
formatyes1.
title, descriptiontitle onlyMarket name and description, LocalizedText.
metadata.categories, metadata.labelsnoObjects mapping an id to { "title": LocalizedText }.
metadata.sortKeysnoObject mapping an id to { "title": LocalizedText, "order": "asc" | "desc" }; order is the initial direction.
pluginsyesPlugins in the market's default order.
Plugin fieldRequiredMeaning
nameyesnpm package name, unique in the index.
title, descriptionnoLocalizedText; the card shows name without a title.
iconnoInline data: URL (SVG, PNG, JPEG, or WebP, at most 32 KiB) or URL, as described above.
authornoDisplay text.
homepagenoAbsolute https: or http: URL of a page about the plugin; the plugin page links it.
repositoryno{ "url": string, "directory"?: string }: the source repository's web page, and the package directory inside it. The plugin page links it as Source code.
metadata.categorynoOne declared category id.
metadata.labelsnoDeclared label ids.
metadata.sortKeysnoObject mapping declared sort-key ids to numbers, such as downloads or ratings.
versionsyesAt least one version, in any order.
Version fieldRequiredMeaning
versionyesExact SemVer version, unique within the plugin.
publishTimestampyesPublish time in Unix seconds.
sourceyes{ "type": "npm", "registry"?: url }, or { "type": "git", "url": https-url, "commit": 40-hex-sha, "path"?: directory }.
engines.dshnoSemVer range of DSH versions this version runs on; absent means any.

DSH installs an npm version as name@version, asking registry first when present, and a Git version as git+<url>.git#<commit> with &path:/<path> for a package in a subdirectory. engines.dsh should match the package's own engines.dsh, which DSH checks again at installation; a package without one is checked against its @deepseek-ai/dsh* peer dependencies instead. The format note defines every rule.

Further Exploration ​

Dev Note ​

None.