Publish one validated DSH plugin package to the DeepSeek Harness distribution
channels and verify each channel can load it. Input is the finished package
source produced by dsh-plugin-creator; this skill owns everything after the
commit: validation, repo gates, per-channel release, and load verification.
There is no official DSH plugin marketplace. The three supported channels
are npm, git, and tarball; GitHub's dsh-plugin topic is the discovery
mechanism. Publish the same plugin across as many channels as the user's
distribution intent needs, keep channel state out of canonical source, and
report evidence per channel.
Triggers
Activate when
- The user says “publish this DSH plugin”, “list the plugin”, “push to npm”, “cut a release”, “export a tarball for the user to install”.
- The user asks to publish, release, distribute, upload, or package an existing DSH plugin.
Do not activate when
- The user wants to create, implement, or modify a plugin; hand it to
dsh-plugin-creator。 - The user merely wants to locally verify that the plugin can load (
dsh --profile demo --dump-config), and has no publishing intent.
Product boundary
- Input is a local plugin package that already passes
dsh-plugin-creator's gates:package.jsoninvariants hold,dsh.bundle.patch(ordsh.plugin.jsonfor the yoda-style registry channel) is present, and no stale build artifacts sit in the tree. - Publishing updates only the target plugin's code, never the whole
harness. A plugin is often developed as a workspace member inside the
deepseek-harnessmonorepo (e.g.packages/client/ui-plugin-market) but published from its own repository (e.g.lovstudio/dsh-plugin-marketplace; such members are listed inscripts/release/families.tsasexternalRepositoryMembers). In that case the release diff is the plugin's own files only: sync the changed plugin source plus its committed build artifacts to the standalone repo, and leave every other harness change (unrelated in-flight features, other packages, root manifests) untouched. Keep the standalone repo's self-referencing import style — monorepo-internal package references such as@deepseek-ai/dsh-host-plugin-market-githubmap to the plugin's own exports (@lovstudio/dsh-plugin-marketplace/...) and must not be copied over. - When the user does not name a channel, default to npm for
@lovstudio/dsh-*plugins whosepublishConfig.accessispublic, and to git for plugins meant to be consumed from source. Do not ask a channel-selection question when the request omits channels. - A request may select multiple channels in one run.
- Version, visibility, and target account are publishing inputs. Reuse the version from the source package; ask only when the user wants a bump that the current manifest does not imply.
- Keep channel metadata, credentials, staging files, and archives outside canonical source.
- Do not invent a registry or marketplace that does not exist. If the user
asks to "list on the DSH marketplace", explain the three real channels and the
dsh-plugintopic, then proceed on those.
Supported channels in this version:
- npm — publish a prebuilt
lib/(or plainindex.js) bundle sodsh plugin add <pkg>installs ready-to-load code. - git — push the source repo, tag a release, and ship a
preparescript sodsh plugin --profile <name> add github:owner/repo#<sha>builds on install. - tarball —
pnpm packa self-contained archive for offline / review installs. - community mirror (optional) — register an out-of-tree plugin under
packages/community/in thedeepseek-ai/deepseek-harnessrepo so it ships with the harness source tree. - discovery topic — add the
dsh-pluginGitHub topic (and, for lovstudio plugins,dsh,deepseek-harness) so the official discovery surface finds it.
For any additional platform, follow references/publish-dsh.md and verify its
current official name, submission contract, public URL, and completion signal
before implementing an adapter. Never call an upload dialog a completed
publication.
Workflow (MANDATORY)
Step 0: Resolve roots and settings
- Resolve this Skill as
SKILL_DIR. - Resolve the plugin source from an explicit path, current directory, or
conversation. Confirm it is a DSH plugin (has
dsh.bundleordsh.plugin.json). - Distinguish the development tree from the publishing repository. All
lovstudio plugins are developed under
~/lovstudio/dsh-plugins/, one standalone git repository per plugin (e.g.~/lovstudio/dsh-plugins/dsh-plugin-marketplace); each is installed into the harness locally for testing and published from its own repository. When a plugin still lives inside thedeepseek-harnessmonorepo as a workspace member, that member is only the source of the plugin's changes and the standalone repo is the release target. Confirm which one the user means before publishing. - Resolve the DSH harness checkout (for gates and the optional community
mirror) from the repo where the plugin was authored, or
$DSH_HARNESSif set. When publishing from a standalone plugin repo, the gates run there — not from the harness root.
Step 1: Validate canonical source
Check that the source has no generated release artifacts, no platform
metadata, and no uncommitted surprises. Record: package name, version,
dsh.bundle / dsh.plugin.json shape, files field, git state, and whether a
remote already exists.
Key package.json invariants (from the harness packages/AGENTS.md /
docs/cookbook/adding-a-package.md): type: module; entry points declared;
files exact (no src, maps, or stale root declarations); @deepseek-ai/cordis
in peer + dev deps at the same range; every dsh peer dep mirrored into devDeps.
A @lovstudio/dsh-* external plugin additionally sets
publishConfig.access: "public" and keywords including dsh-plugin.
Step 2: Run the repo gates
Run the gates from the plugin's own publishing repository — the standalone repo when the plugin publishes from one, otherwise the harness root. Never run the whole-harness gate suite for a plugin that publishes from its own repo:
# Standalone plugin repo
pnpm install
pnpm run typecheck && pnpm run lint && pnpm run build
pnpm pack --dry-run # proves the publish payload packs
# Plugin developed inside the harness monorepo but publishing from its own repo:
# validate only the plugin's changed surface (its package tests/build), not the
# harness-wide suite — unrelated in-flight harness changes must not block or
# leak into the plugin release.
Then run only the checks the changed surface reaches — do not default to the full suite. Any failure blocks publication.
Step 3: Decide channels and release model
If channels are explicit, proceed. If none are named, select npm (for public
@lovstudio/*) and/or git (for source installs) and proceed without asking.
For each channel, resolve only required fields:
- version to publish (reuse the manifest version unless the user asked for a bump);
- npm package name, visibility, and dist-tag;
- git remote, tag name, and whether to pin installs to a commit;
- community mirror group under
packages/<group>/(defaultcommunity).
Do not ask users to choose implementation details such as staging layout, archive format, or adapter order.
Step 4: Build a per-channel plan
Read references/publish-dsh.md, then execute only the selected channels.
Keep independent state for each target so one failure does not masquerade as a
successful multi-channel release.
Build the release diff before touching any channel. The release diff is the target plugin's own changes only. When the plugin is developed inside the harness monorepo and published from a standalone repo:
- Compare the plugin's monorepo member tree against the standalone repo to find the functional delta (for example a one-line icon fix). Ignore monorepo-internal import-name differences — the standalone repo keeps its self-referencing style.
- Apply only that delta to the standalone repo: the changed source file(s),
the committed build artifacts they feed (e.g.
lib/client.cjs), thepackage.jsonversion bump, and theCHANGELOG.mdentry. - Do not copy over other harness files, unrelated in-flight features, or the
root manifests.
git statusin the standalone repo must show exactly the plugin release files before committing.
Step 5: Publish to npm
Read the npm section of references/publish-dsh.md. Ensure the build output is
in the published files (run prepublishOnly: pnpm build if the manifest
declares it). Then:
pnpm publish --access public
git tag v<VERSION>
git push origin v<VERSION>
Record the published version, dist-tag, and the package page URL. Verify with
npm view <pkg>@<version> that the exact version and expected files are live.
Step 6: Publish to git
Read the git section of references/publish-dsh.md. Ensure a self-contained
prepare script exists (builds entry points from source; no sibling-monorepo
assumptions). Push the release commit and tag, then verify the git-install
path on a clean profile:
dsh plugin --profile demo add github:<owner>/<repo>#<sha>
If pnpm >= 10 blocks the prepare script, record the exact package key the
allowlist needs (allowBuilds in the profile's pnpm-workspace.yaml) as a
follow-up for the user, not as a silent pass.
Step 7: Ship a tarball
Read the tarball section of references/publish-dsh.md. Build a clean archive
outside canonical source:
pnpm pack --out /tmp/<pkg>-<version>.tgz
dsh plugin --profile demo add /tmp/<pkg>-<version>.tgz
Record the archive path, checksum, file count, and the successful add.
Step 8: Community mirror and discovery topic (optional)
When the plugin should ship with the harness, mirror it under
packages/community/ (follow docs/cookbook/adding-a-package.md), or run the
standard dsh PR flow for the deepseek-ai/deepseek-harness repo. Tag the
GitHub repo with the dsh-plugin topic (and deepseek-harness). Record the
topic set and the PR/release state.
Step 9: Verify load in the harness
Whatever the channels, the final gate is that the plugin loads:
dsh --profile demo --dump-config # expect a "# == <pkg>" layer
dsh --profile demo # boots without error
A parsed archive or a pushed tag is only published; the plugin is live
only when the layer appears and the harness boots.
Step 10: Multi-channel report
Report each target separately:
| Channel | State | Version/artifact | Evidence | Follow-up |
|---|---|---|---|---|
| TARGET | prepared/published/live | VALUE | URL or local path | ACTION |
Use precise states. published and live represent different outcomes.
Dependencies
- Node.js >= 20, pnpm >= 10
dshCLI on PATH (or run gates viapnpm dshfrom the harness source)git+ GitHub CLI for git/topic/release operations- npm credentials for the npm channel
Local development
Validate this publisher Skill's own source with the harness gates, or inspect
references/publish-dsh.md for the grounded contract behind each step.
Runtime context (shared)
Before running, read this Skill package's skill.yaml, with the host providing the skill-runtime/v1 context. The field resolution order is: current request, project context, personal Preferences, brand Profile, general defaults.
- Use only the fields declared in the Manifest; the Profile stores public brand facts, and Preferences stores personal work preferences.
required: trueWhen a field is missing, ask the user one focused question according to the Manifest's question configuration; save the answer only after the user explicitly agrees.- Errors provide a copyable
context_id, field path, and source, and diagnostic content avoids secrets, full private paths, and raw configuration.
References
references/publish-dsh.md— the grounded per-channel SOP with authoritative sources.dsh-plugin-creator— the companion skill that produces the validated package this skill publishes.
General feedback loop
When the user raises modification feedback during a Skill-driven task, before continuing with the current artifact you must:
- First determine whether the feedback is
task-specific(this time only) orreusable(reusable across tasks). task-specificOnly modify the current task; do not change the Skill.reusableFirst determine the scope: for domain rules, first update the corresponding canonical Skill; for rules that apply to all Skills, first update the shared specification.- After completing the rule update, versioning, lint, and distribution verification, then apply the modification to the current task.
reusableThe modification invalidates any previous “confirm”, “continue”, or “go ahead”; after completing the current artifact modification and read-back, you must stop and wait for the user's next instruction, without automatically proceeding to publishing, committing, or any other external write.