Install
$ agentstack add skill-rayyeung1989-dsh-plugin-development-dsh-plugin-development ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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: . 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/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: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(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, '') 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.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: RayYeung1989
- Source: RayYeung1989/dsh-plugin-development
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.