agentleFS
RayYeung1989RayYeung1989/dsh-plugin-development/SKILL.md

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

  • Other versions5 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 5

    1. NanmiCoder/dsh-agent-teams★ 2.8ksame name
    2. GZX2211/dsh-Visual-Workflow★ 59same name
    3. JerryChaox/dsh-plugin-development★ 1same name
    4. Practice019/agent-skills★ 0same name
    5. 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
  1. Distinctive:

    Never invent the API. Before writing code, read the real interfaces:

    line 12
  2. Very specific:

    Every listener, subscription, timer, and token override must be disposable and owned inside apply (ctx.on(...), ctx.effect(() => disposer), …

    line 101

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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.ts files under the dsh installation. Find it with node -p "require.resolve('@deepseek-ai/dsh/package.json')" — if that throws MODULE_NOT_FOUND (global install not on the resolution path), use readlink -f "$(which dsh)" and walk up to the @deepseek-ai/dsh package dir, or npm root -g. The whole @deepseek-ai/* surface lives in that package's node_modules. Read lib/types/**/*.d.ts of 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) and dsh web --dump-default-config (bundle layers only). Note: dumps rewrite the profile's cordis.yml, so on a read-only $DSH_HOME they fail with EROFS — 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.directory points 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> whose package.json declares dsh.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 in bundles order → profile cordis.patch.yml → $DSH_HOME/cordis.patch.yml → --patch overlays.
  • Rows are addressed by id; the last write wins per row; a patch replaces the row's whole config (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 with dsh.client in its package.json.

Standard workflow

  1. Locate install & target profile — echo $DSH_HOME, dsh --version, ls $DSH_HOME/profiles. Confirm which profile the plugin targets (web for the GUI, headless for CLI runs).
  2. Inspect the composed tree — dsh web --dump-config. Find the row id to add or override; copy the shape of a similar existing row.
  3. 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.
  4. Scaffold from templates/ in this skill.
  5. Write code against real surfaces — read the installed .d.ts of every service/event you touch (sessions, llm, timer, theme, slots, …). See references/services-events.md.
  6. 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).
  7. Verify (loop) — dsh web --dump-config shows your row; boot dsh web; client plugins appear as rows in WebUI 设置 → 插件管理; server behavior via a dsh --profile headless "..." smoke run or session logs.
  8. Debug with the failure table below.

Host vs Client

Want to …SideKey services / entry points
Files, processes, network, timers, sessions, LLM, dynamic model toolsHostsessions, 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 UIClienttheme, slots, modules, settings, remote
Host data shown on the clientBothHost 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 use React.createElement (React arrives via require('react')).
  • Optional services: ctx.get('x') with an absence check. Declare inject: ['x'] only for hard dependencies, or you get service "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/structuredClone live Service / Session / Event / Slot objects — extract the scalar leaves you need.
  • A patch config: replaces the whole row config; use !!js expressions 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:web watcher rebuilds client bundles.
  • Install client-only and dual-half packages with the dsh.client manifest and a ./client export, or the browser half is never served.

Common failures

SymptomCheck first
Row missing / plugin not loadeddsh 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 declaredctx.x used without inject; switch to ctx.get('x') or declare the hard dependency
cannot get property "timer" without injectTimers are a Service, not a global: declare inject: ['timer']
Config validation error at bootschemastery Config vs patch config mismatch; --dump-config shows the composed value
Client half never appearsdsh.client malformed (platform string, inject string[], immediately boolean), missing ./client export, or no page reload
Client render errorBrowser console; JSX/TS/import/Node globals in lib/client.js
Plugin loads but has no effectEvent names / payloads drift per DSH version — re-read the installed .d.ts
Dependency resolution errorThe 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.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.