dsh-plugin-development
Skill2 starsChanged 3 months agoMITView on GitHub
Use when developing, modifying, debugging, installing, or verifying a dsh plugin (DeepSeek Harness plugin / dsh插件 / DSH插件) — a Cordis plugin package that runs inside DeepSeek Harness profiles (web / headless / custom). Triggers include "开发dsh插件", "写个dsh插件", "给DSH写插件", "deepseek-harness插件", extending the DeepSeek Harness WebUI (theme, sidebar, settings pages, tool cards, chat UI), hooking host behavior (session events such as user/message or turn/end, LLM requests, dynamic tools), or wiring a plugin into cordis.patch.yml and a profile via pnpm / dsh plugin. Also use when debugging why a plugin fails to load, activate, or render.
- Reads credentials
5 other projects use a version of this.
Adopted by
Most recently taken up by
- NanmiCoder/dsh-agent-teamstheir own version, first seen Oct 8, 2026
- GZX2211/dsh-Visual-Workflowtheir own version, first seen Sep 24, 2026
- Practice019/agent-skillstheir own version, first seen Sep 9, 2026
- striveh/dsh-plugin-developmenttheir own version, first seen Aug 21, 2026
- JerryChaox/dsh-plugin-developmenttheir own version, first seen Aug 15, 2026
Other versions5 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 5
- NanmiCoder/dsh-agent-teams★ 2.8ksame name
- GZX2211/dsh-Visual-Workflow★ 59same name
- JerryChaox/dsh-plugin-development★ 1same name
- Practice019/agent-skills★ 0same name
- striveh/dsh-plugin-development★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 12
Never invent the API. Before writing code, read the real interfaces:
- Very specific: line 101
Every listener, subscription, timer, and token override must be disposable and owned inside apply (ctx.on(...), ctx.effect(() => disposer), …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Develop DeepSeek Harness (dsh) Plugins
Build, install, and debug dsh plugins: npm packages whose Cordis plugin entries extend a DeepSeek Harness profile. This skill works from any agent runtime (Claude Code, Codex, Hermes, OpenClaw, …) using only file + shell tools — it does not assume DSH-internal tools.
Ground truth first (golden rule)
Never invent the API. Before writing code, read the real interfaces:
- Installed packages:
.d.tsfiles under the dsh installation. Find it withnode -p "require.resolve('@deepseek-ai/dsh/package.json')"— if that throwsMODULE_NOT_FOUND(global install not on the resolution path), usereadlink -f "$(which dsh)"and walk up to the@deepseek-ai/dshpackage dir, ornpm root -g. The whole@deepseek-ai/*surface lives in that package'snode_modules. Readlib/types/**/*.d.tsof the exact package (e.g.@deepseek-ai/dsh-session,@deepseek-ai/dsh-llm) for the service/event surface of the installed version. - Composed profile tree:
dsh web --dump-config(with the user layer) anddsh web --dump-default-config(bundle layers only). Note: dumps rewrite the profile'scordis.yml, so on a read-only$DSH_HOMEthey fail withEROFS— then read the profile files and installed patch files directly. - CLI surface:
dsh --help,dsh --version,dsh web --help. - Source repo: https://github.com/deepseek-ai/deepseek-harness. Every package's
package.json→repository.directorypoints to its source dir (e.g.apps/cli,packages/bundle/base,packages/session/...).
Architecture in one screen
- DSH is a Cordis plugin framework. A profile (e.g.
web) is$DSH_HOME/profiles/<name>whosepackage.jsondeclaresdsh.profile.bundles— an ordered list of plugin-bundle layers (web =@deepseek-ai/dsh-base+@deepseek-ai/dsh-web-app). - Each bundle contributes a patch (
cordis.patch.yml). The composed tree is: bundle patches inbundlesorder → profilecordis.patch.yml→$DSH_HOME/cordis.patch.yml→--patchoverlays. - Rows are addressed by
id; the last write wins per row; a patch replaces the row's wholeconfig(no merging).- id: <row>addresses an existing row;- insert:adds new rows. - A dsh plugin is any npm package a patch row's
name:points at. It has a host half (Node: services, events, tools, side effects) and optionally a browser half (Web UI/theme) declared withdsh.clientin itspackage.json.
Standard workflow
- Locate install & target profile —
echo $DSH_HOME,dsh --version,ls $DSH_HOME/profiles. Confirm which profile the plugin targets (webfor the GUI,headlessfor CLI runs). - Inspect the composed tree —
dsh web --dump-config. Find the row id to add or override; copy the shape of a similar existing row. - Decide host vs client (table below). Prefer the side closest to the data owner; a pure-UI plugin keeps its host half a no-op carrier.
- Scaffold from
templates/in this skill. - Write code against real surfaces — read the installed
.d.tsof every service/event you touch (sessions,llm,timer,theme,slots, …). Seereferences/services-events.md. - Register + install — patch row (
- insert:for a new row,- id:to override) +dsh plugin --profile web add <spec>(local path,file:,link:,github:user/repo#tag, or registry name). - Verify (loop) —
dsh web --dump-configshows your row; bootdsh web; client plugins appear as rows in WebUI 设置 → 插件管理; server behavior via adsh --profile headless "..."smoke run or session logs. - Debug with the failure table below.
Host vs Client
| Want to … | Side | Key services / entry points | ||||
| Files, processes, network, timers, sessions, LLM, dynamic model tools | Host | sessions, llm, agents, skills, subagents, settings, credentials, fs, sandbox, approval, timer | ||||
| Hook conversation lifecycle (turn / step / message events) | Host | `ctx.on('turn/end' | 'user/message' | 'assistant/message' | 'step/start' | …)` |
| Page theme, layout, sidebar, settings pages, tool cards, chat UI | Client | theme, slots, modules, settings, remote | ||||
| Host data shown on the client | Both | Host service/event + client slot; RPC via the typert gateway (ctx.remote, see references) |
Plugin anatomy (minimal)
Host-only entry (lib/index.js, ESM — "type": "module"):
import z from '@deepseek-ai/schemastery'
export const name = 'example-turn-logger'
export const inject = ['timer'] // hard dependencies only
export const Config = z.object({ // validated against the patch `config:`
greeting: z.string().default('hi'),
})
export function apply(ctx, config) {
ctx.on('turn/end', (payload) => {
// verified payload (dsh 0.1.0-rc.6): { turn: number, reason: TurnEndReason }
// re-check the installed @deepseek-ai/dsh-session/lib/types/types.d.ts first
console.log(config.greeting, payload.turn, payload.reason.kind)
})
ctx.effect(() => ctx.interval(() => console.log('tick'), 60_000))
}The Loader also accepts a default-export function/class (a class constructed with (ctx, config) and calling super(ctx, '<serviceName>') publishes a Service) or a default-export object { apply, name?, inject?, Config? }.
Client half (lib/client.js, plain JS — no import/JSX/TS) plus the manifest in package.json:
"dsh": { "client": { "platform": "web", "inject": ["@deepseek-ai/dsh-client-ui-theme"], "immediately": true } },
"exports": { "./client": "./lib/client.js" }window.__ModuleLoader__.load({
id: 'example-client',
factory: (require) => {
var module = { exports: {} }
var exports = module.exports
exports.apply = (ctx) => {
const theme = ctx.get('theme')
if (theme !== undefined) {
ctx.effect(() => theme.overrideTokens('example', {
'--dsw-alias-brand-primary': { light: '#c96442', dark: '#d97757' },
}))
}
}
return module.exports
},
})Rules (violations fail at load or render)
- ESM only on the host; plain JS only in the browser half (no
import, JSX, TypeScript, decorators). Browser UI must useReact.createElement(React arrives viarequire('react')). - Optional services:
ctx.get('x')with an absence check. Declareinject: ['x']only for hard dependencies, or you getservice "x" is not declared/cannot get property "timer" without inject. - Every listener, subscription, timer, and token override must be disposable and owned inside
apply(ctx.on(...),ctx.effect(() => disposer), retained disposers). No module-scope side effects, no process/page-wide globals. - Host↔client values must be JSON-safe. Never
JSON.stringify/structuredClonelive Service / Session / Event / Slot objects — extract the scalar leaves you need. - A patch
config:replaces the whole row config; use!!jsexpressions for dynamic values (!!js process.env.X,!!js ctx.webStartup.port ?? 3080,!!js dshHomePath('sessions')). - Client plugins need a full page reload after install. HMR auto-reload only exists while the
pnpm run dev:webwatcher rebuilds client bundles. - Install client-only and dual-half packages with the
dsh.clientmanifest and a./clientexport, or the browser half is never served.
Common failures
| Symptom | Check first |
| Row missing / plugin not loaded | dsh web --dump-config; row id/name correct; package resolvable (two-anchor resolution: profile node_modules, then the flat fallback $DSH_HOME/profiles/node_modules) |
service "x" is not declared | ctx.x used without inject; switch to ctx.get('x') or declare the hard dependency |
cannot get property "timer" without inject | Timers are a Service, not a global: declare inject: ['timer'] |
| Config validation error at boot | schemastery Config vs patch config mismatch; --dump-config shows the composed value |
| Client half never appears | dsh.client malformed (platform string, inject string[], immediately boolean), missing ./client export, or no page reload |
| Client render error | Browser console; JSX/TS/import/Node globals in lib/client.js |
| Plugin loads but has no effect | Event names / payloads drift per DSH version — re-read the installed .d.ts |
| Dependency resolution error | The import isn't resolvable from the profile; either it is not an in-box package (declare it in dependencies, pnpm installs it) or the package is not installed |
Installing this skill into an agent runtime
Copy this folder into the runtime's skills directory:
- Cross-runtime (Codex, Copilot CLI, Gemini CLI, and DSH itself scan it):
~/.agents/skills/dsh-plugin-development/ - Claude Code:
~/.claude/skills/dsh-plugin-development/ - DSH home:
$DSH_HOME/skills/dsh-plugin-development/ - Hermes / OpenClaw / others: drop the folder wherever that tool scans for
SKILL.md(e.g. Hermes plugin dirs, OpenClaw skill dirs).
References & templates
references/plugin-package.md— full package / entry / manifest / patch / CLI contract, verified against dsh 0.1.0-rc.6.references/services-events.md— service & event surface and how to enumerate it at runtime.templates/server-plugin/— host-only starter (Config + events + timer).templates/client-plugin/— browser-only starter (theme token override + CSS, theme-proven pattern).templates/dual-half-plugin/— host service + browser UI starter with RPC notes.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

