Communitygithub.com

zimodzh/dsh-plugin-dev-skills

An Agent Skills skill for developing DeepSeek Harness (DSH) plugins(开发 DSH 插件的 Agent Skill)——插件/服务/事件/工具/LLM 适配器/打包安装的标准。Works with Claude Code, Codex, DSH, VS Code Copilot & any compatible agent.

dsh-plugin-dev-skills 是什么?

dsh-plugin-dev-skills is a Claude Code agent skill that an Agent Skills skill for developing DeepSeek Harness (DSH) plugins(开发 DSH 插件的 Agent Skill)——插件/服务/事件/工具/LLM 适配器/打包安装的标准。Works with Claude Code, Codex, DSH, VS Code Copilot & any compatible agent.

兼容平台✓Claude Code✓Codex CLI~Cursor
npx skills add zimodzh/dsh-plugin-dev-skills

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

DSH Plugin Development Standard

This skill is the definitive standard for developing DeepSeek Harness (DSH) plugins: it converges conventions scattered across DSH's official documentation (tutorials, reference manuals, and generation catalogs) into an actionable workflow, hard rules, and a completion checklist. Everything in DSH is a plugin – model adapters, tool registries, session logs, and even the agent loop itself – so acting by this skill means you are extending DSH the same way it was architected.

Scope

  • In-repository, file-based DSH plugin development: writing plugin packages, registering cordis.yml lines, patch overlays, developing tools, integrating models, packaging and installation.
  • Workspace package development within the DSH monorepo (packages//) also falls under this skill (references/workspace-package.md).
  • This skill does not cover: dynamic in-session plugins (cordis_define/cordis_run flow) and agent preset composition editing – these are covered by dedicated deployment skills or official tools.

Hard Rules (must be followed in every scenario)

  1. Interfaces are based on generated references. Service names, public methods, event signatures, and ctx keys must be based on the auto-generated subsystem pages and TypeScript interfaces from the repository; do not infer a full API from service names, examples, or old code, and do not maintain a separate static list.
  2. All contributions are side-effects. Everything you register through ctx (event listeners, tools, adapters, ctx.effect) is automatically revoked when the plugin is unloaded; do not create process-level or page-level side-effects in module scope; for third-party subscriptions that do not return a disposer, proactively find out the cleanup mechanism.
  3. Waterfall listeners must call next(). Not calling next() intentionally short-circuits downstream (used for interception/gateways) – it is not optional.
  4. Fail loudly. Throwing an exception in apply terminates the process; configuration validation failures must produce explicit errors; schemas should express complete constraints on their own – do not silently swallow errors at runtime.
  5. Declare required dependencies with inject, optional dependencies with ctx.get() and a null check. Do not use inject to bypass undefined checks; do not directly access ctx.xxx for unregistered services – unregistered services evaluated via the service resolver may yield undefined.
  6. All configurations must use Schemastery. Export interface Config and a Schema with the same name, with default values defined in the schema; do not export a plain object as Config; any parameter that may vary across deployments must be in the config.
  7. Tool execute returns canonical JSON values, not content blocks. Human-readable text goes in output.render; deployment strategies/hooks must not be built into the tool itself.
  8. Model-visible means already recorded. Any new model-visible input must fall within a mechanism that allows session logs to be reconstructed (via a new persistent event or through agent.inject()), with runtime invariant assertions.
  9. npm settings panels prefer ctx.connection.rpc. Browser-side settings panels call main-process methods, preferring Connection RPC (ctx.connection.rpc.handle + ctx.connection.rpc.call); boilerplate is in references/connection-rpc.md. Bare @Remote, handwritten typert manifests, and createRequire patching of harness source code are prohibited. Paths produced by the full Typert generator and exported via package.json as ./typert + ./remote, consumed by ctx.remote.$mount(), remain valid.

Standard Workflows

Scenario A: Creating a New Plugin

  1. Determine what the plugin will contribute (service? tool? listener?), and use the "Placement of New Behaviors" table in references/seams.md to select the mechanism.
  2. Create src/.ts, exporting name, inject (optional), and apply(ctx, config?). Start with the function form; switch to a Service class form when you need to expose a service externally.
  3. Local development loop (source code checkout):
mkdir -p scratch-plugin/src
# scratch-plugin/cordis.yml -- patch overlay; plugin path must be absolute
- insert:
    - id: hello
      name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
pnpm dsh web --patch ./scratch-plugin/cordis.yml   # opens http://127.0.0.1:3080
  1. Verify loading and unloading: startup log appears, resources are properly cleaned upon deactivation (references/plugin-anatomy.md).

Scenario B: Adding a Tool to a Model

  1. inject: ['tools'], use defineTool (name/description/parameters/output/execute).
  2. Implement according to the execute convention in references/tools.md: schema DSL declares parameters and output, execute returns canonical values, respects exec.signal, optional presentationMeta/UI cards.
  3. When policies are needed, hang them on tools/* events (pre-execute/guard/execute/post-execute/result), do not hardcode policies into the tool body (see references/plugin-forms.md for an access-control example).
  4. Restart and let the model actually call the tool to verify.

Scenario C: Replaceable Capabilities (Multiple Providers)

  1. Split according to references/three-roles.md into three packages: Definition / Provider / Consumer (merge roles as needed, do not pre-emptively split).
  2. Definition owns Request/Result types and an abstract Service; Provider implements it; Consumer exposes it as a tool or a consumer of the service.
  3. In cordis.yml, list only the Provider and Consumer lines; swapping a provider only requires changing one line.

Scenario D: Integrating a New Model Provider

  1. Extend LlmAdapter to implement stream(), outputting chunks according to the StreamChunk protocol; use LlmError with a stable code for errors (or end in-band with finish { kind: 'error' | 'aborted' }); combine attributionHeaders() and pass signal for each HTTP request.
  2. ctx.llm.registerAdapter(['<provider>'], adapter); optionally override resolveModel()/listModels().
  3. In the composition, configure the agent-loop's provider/model for verification. See references/llm-adapter.md (includes 7 protocol obligations).

Scenario E: Packaging and Installation Delivery

  1. Create a composition package: package.json declares dsh.bundle (pointing to cordis.patch.yml), patch lines reference plugins by package name; library-only packages do not declare dsh.bundle.
  2. Install: dsh plugin --profile <name> add <pkg>; first run dsh --profile <name> --dump-config to verify the layer, then start.
  3. Remember layer order and full-line replacement semantics (references/packaging.md).

Scenario F: Creating a New Package in the DSH Monorepo

Follow the file-by-file checklist in references/workspace-package.md: create the package (package.json invariants/tsconfig/src/README) → register in root configuration → package topology and naming (role vocabulary) → README Model Experience structure → verification commands.

Decision Quick-Reference

I want to…MechanismDetails
Expose capabilities to other pluginsService (class form)references/services.md
Consume existing capabilitiesinject or ctx.get()references/services.md
Inter-plugin communication / extension pointsctx.on / ctx.emit events (five dispatch modes)references/events.md
Allow user configurationConfig + Schemasteryreferences/config.md
Add capabilities to a modeldefineTool → ctx.tools.register (or raw JSON Schema)references/tools.md
Connect a new model providerLlmAdapter + ctx.llm.registerAdapterreferences/llm-adapter.md
Build replaceable capabilitiesThree roles (Definition/Provider/Consumer)references/three-roles.md
Distribute a pluginComposition package + profilereferences/packaging.md
Look up built-in services / placementseam directory, architecture mapreferences/seams.md
Scopes / service storage / Fiber APIctx.extend/isolate/provide/mixin, fiber.*references/context-api.md
Hooks / UI / panels / protocol bridge pluginsFive extension forms + function-to-mechanism mapreferences/plugin-forms.md
Browser-side panel calling main-process servicectx.connection.rpc.handle/call, endpoint + envelopereferences/connection-rpc.md
Create a new package / naming in the monorepoWorkspace package checklist + role vocabularyreferences/workspace-package.md

Pre-Completion Checklist

  • Interfaces checked against generated references (service/event/ctx keys are based on generation), no API guessing from names.
  • All registrations go through ctx (events/tools/adapters/effect), cleanable on unload; order-sensitive cleanup placed within the same ctx.effect.
  • Required dependencies correctly declared via inject; optional dependencies have undefined-handling.
  • Plugins with configuration: Config uses Schemastery, default values in schema, invalid configuration fails loudly on load.
  • Tools (if any): execute returns canonical JSON values; render handles human readability; policies go through tools/* events; respects exec.signal; concurrency safety declared via isConcurrencySafe (not declared → exclusive).
  • Waterfall listeners: call and return next() (unless intentionally short-circuiting).
  • LLM adapters: StreamChunk protocol complete (chunk pairing, index based on first occurrence, usage before finish, arguments as raw JSON strings throughout); errors follow one of two valid paths; unsupported fields throw UNSUPPORTED; native replay uses finish.replayState; attributionHeaders and signal passed.
  • Composition lines and layer order correct; new lines visible in --dump-config; no residual registrations after HMR/restart.
  • If model-visible content changes: it falls within a mechanism that allows log reconstruction.
  • Browser-side settings panels: prefer ctx.connection.rpc.handle/call; bare @Remote, handwritten typert manifests, createRequire patching of harness source code prohibited; full Typert generator + ./typert + ./remote output remains valid.
  • New workspace package: package.json invariants, exactly one aggregate, naming conforms to role vocabulary, README has Model Experience structure, and constraints/typecheck/lint/build/hygiene all green.

Reference Files (load on demand, do not read all at once)

Full index and "when to read" table at references/README.md.

  • references/plugin-anatomy.md – read when writing/modifying a plugin, handling lifecycle or HMR
  • references/services.md – read when defining or consuming services, injecting dependencies
  • references/events.md – read when communicating via events, listening to extension points
  • references/config.md – read when making a plugin configurable
  • references/context-api.md – read when using scopes, service storage, or the Fiber API
  • references/three-roles.md – read when splitting replaceable capabilities
  • references/tools.md – read when developing model tools
  • references/llm-adapter.md – read when integrating a new model provider
  • references/plugin-forms.md – read when writing hooks/UI/protocol bridge plugins
  • references/connection-rpc.md – read when an npm settings panel needs to call main-process methods; also read when encountering bare @Remote / handwritten manifests / createRequire source bridges
  • references/packaging.md – read when packaging, installing, or delivering a plugin
  • references/workspace-package.md – read when creating a new package inside the monorepo
  • references/seams.md – read when looking up built-in services, placement, or architecture maps

Validation

  • Format self-check: name is kebab-case and matches the directory name; description is non-empty and concise (this skill is under 500 characters); body uses standard Markdown; all referenced reference files actually exist.
  • Directory naming: this skill's name (name) is dsh-plugin-dev, which differs from the hosting repository name dsh-plugin-dev-skills – after cloning/extracting, the folder must be renamed to dsh-plugin-dev (matching name), otherwise loaders that address by directory name may fail to discover this skill.
  • In environments with the skills-ref CLI: run skills-ref validate ./dsh-plugin-dev
  • Trigger regression: after modifying the description, run the eval set from evals/trigger-queries.json (method in the repository evals/README.md).
  • Behavior validation: walk through Scenario A with a minimal plugin (load log + unload cleanup), then Scenario B with a greet tool.

相关技能