使用方法
- 复制安装命令,在自己的智能体环境安装前先检查源码包。
- 从原始文档核对所需工具、凭据和支持的宿主。
- 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/alber70g/skills --skill deepseek-harness-plugin-dev开始前需了解
- 安装不包含模型订阅、API 额度或访问文件的权限。
- 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。
DeepSeek Harness plugin development
Use this skill to implement real DeepSeek Harness plugins, not generic Node plugins. DeepSeek Harness is composed from Cordis plugins mounted into shared contexts; tools, model adapters, services, storage, policy, and agent behavior are extension points in that plugin tree.
Cordis mental model
Reason in these concepts before designing a non-trivial plugin:
- Plugin — a lifecycle-owned unit mounted by Cordis. Usually a function with
apply(ctx); aServicesubclass is also a plugin. - Context (`ctx`) — the scoped repository of services and the entry point for Cordis registrations, events, effects, and child plugins.
- Service — a named capability exposed as
ctx.<key>. Consumers depend on the capability name, not a concrete provider import. - `inject` — declarative required service dependencies. It controls readiness and reloading; YAML row order is not dependency management.
- Fiber/lifecycle — every mounted plugin instance owns a Fiber that can be pending, load, become active, unload, and dispose.
- Effect — lifecycle-owned registration/resource. Cordis APIs already create effects; unmanaged resources belong in
ctx.effect()with a disposer. - Event — decoupled runtime communication. Use a service for direct capability calls; use events for announcements, observers, policy/interception, or pipelines.
- Composition —
cordis.ymland patches describe a plugin tree;ctx.plugin()creates a child Fiber with independent lifecycle under its parent.
TypeScript declaration merging only adds compile-time knowledge of a service or event. It does not register anything at runtime.
For anything beyond one obvious registration, read references/cordis-concepts.md before choosing architecture. Then load only the task-specific references below.
First: classify the requested plugin
Choose the smallest fitting shape before writing code:
| Need | Shape | Read next |
|---|---|---|
| Cordis architecture is not already obvious | Mental-model pass | references/cordis-concepts.md |
| Startup behavior or simple registration | Function plugin | references/plugin-basics.md |
| Timers, sockets, watchers, child fibers, teardown, HMR safety | Lifecycle/effects | references/lifecycle-effects.md |
| Model-callable capability | Tool plugin | references/tools.md |
| Shared capability other plugins consume | Service definition/provider | references/services.md |
| Observe, announce, intercept, or pipeline behavior | Event listener/event contract | references/events.md |
| Nested plugin tree, groups, isolation, HMR composition | Composition | references/composition-hmr.md |
| User/deployment-tunable settings | Configurable plugin | references/config-packaging.md |
| Installable/distributable plugin | Bundle | references/config-packaging.md |
| Replaceable provider architecture | Three-role capability | references/capability-design.md |
| Plugin does not load, HMR behaves oddly, wrong config wins | Diagnostics | references/diagnostics.md |
Do not read every reference by default. Load only the references needed for the requested plugin. This is deliberate progressive disclosure.
Core workflow
- Inspect the environment first. If a DeepSeek Harness checkout is available, inspect its current package types, generated Cordis surfaces, nearby implementations, and effective configuration before relying on remembered APIs. Prefer current local source over copied examples.
- Model the plugin in Cordis terms. Identify the plugin boundary, required services, lifecycle-owned resources, direct capabilities, event hooks, and whether child composition is needed.
- Identify the smallest seam. Decide whether this is a function plugin, tool, service/provider, event listener/interceptor, adapter, configuration layer, or bundle. Do not split a simple tool into multiple packages without a real replacement/evolution boundary.
- Declare dependencies explicitly. Use
injectfor required Cordis services. Never rely on row order incordis.ymlas a startup dependency mechanism. - Keep lifecycle ownership inside Cordis. Register listeners, tools, child plugins, and resources through
ctx. Put manual cleanup for unmanaged resources inctx.effect()and return a disposer. - Choose service vs event intentionally. Use services for stable callable capabilities and events for loose coupling, observation, decisions, and pipelines. Do not simulate one with the other without a reason.
- Make tunables configuration. If two deployments may reasonably choose different values, expose them through an exported
Configschema rather than hardcoding them. - Implement the smallest coherent plugin. Prefer a function plugin unless the plugin itself provides a stable service capability.
- Verify in a disposable setup. For source development, load through a patch overlay and confirm the composed config. Exercise the actual registration/execution path and at least one unload/reload path when lifecycle behavior matters.
- Package only when required. A distributable Harness plugin is normally an npm bundle with a
dsh.bundlemanifest pointing at its patch layer. - Report exactly what changed. Include files created/modified, how to run it, how to verify it, and any assumptions tied to the current Harness version.
Non-negotiable implementation rules
- A basic Cordis plugin should expose
apply(ctx);nameis useful metadata. - Required services belong in
inject; a dependent plugin should wait for services instead of polling or depending on YAML order. - If a required service disappears, expect dependent plugins to unload and later reload. Do not retain required service instances outside the owning lifecycle.
- Registrations made through Cordis are lifecycle-owned. Do not add redundant manual unregistration for Cordis-owned registrations.
- Use
ctx.effect()for unmanaged resources such as sockets, timers, subprocess handles, file watchers, or external clients that need explicit cleanup. - When cleanup order matters, keep ordered steps in one disposer; do not assume several async disposers finish serially.
ctx.plugin(child)creates a child Fiber; use it for lifecycle-aware composition rather than manually invoking another plugin'sapply().- Declaration merging for
ContextorEventsis type-only. Runtime service registration/emission/listening must still be implemented. - For configuration, export both the TypeScript
Configtype/interface and a same-named Schemastery schema. Put defaults on schema fields. - For tools, register with
ctx.tools.register(defineTool(...)), declareinject = ['tools'], return a canonical JSON-compatible value matchingoutput.schema, and keep model-facing prose inoutput.render. - Tool executors must honor
exec.signalfor foreground cancellation when the underlying API supports cancellation. - Do not make UI presentation functions perform I/O or depend on time/random/session state; replay must remain deterministic.
- Namespace custom events. Match the documented Cordis dispatch mode (
emit,parallel,serial,bail, orwaterfall) to the contract. - A waterfall observer/middleware that intends downstream behavior to continue must call
next(); omitting it is an intentional short-circuit. - Use class/service form when the plugin provides a stable
ctx.<service>capability; otherwise prefer function form. - For source-checkout Web testing with
--patch, remember that a patch does not relocate module resolution to the patch file's directory. Use a resolvable package name or an appropriate absolute source path. - For standalone Cordis tutorial launchers executed from their scratch directory, relative module paths in that local
cordis.ymlare valid because the loader resolves from that composition context. - Give composition entries stable
ids when they should survive config edits as the same logical plugin instance. - A bundle and a profile are different things. Author the bundle; let
dsh pluginmanage profile dependencies/manifests. - Patch layers replace a targeted row's whole
configvalue rather than deep-merging it. When overriding a row, restate all required config keys. - Treat third-party plugins and install/build scripts as trusted host code. Review source and dependencies before granting build permissions.
Default development path
For a new plugin in a Harness source checkout:
- Create a small plugin source file.
- Create a patch overlay that inserts it with a stable
id. - Start the relevant surface, commonly:
pnpm dsh web --patch ./path/to/cordis.yml- If behavior depends on composition, inspect:
pnpm dsh --profile web --dump-configor the installed-CLI equivalent:
dsh --profile web --dump-config- Exercise the plugin through the real Harness path.
- Trigger one reload/unload cycle when the plugin owns resources, listeners, tools, services, or child plugins.
- Add focused tests next to the owning package when the change is intended to ship.
For a simple starting point, use the templates in assets/. The optional scaffold helper supports the main plugin shapes:
node scripts/scaffold.mjs --name my-plugin --type basic|tool|service|configurable|bundle --out ./my-pluginTreat generated code as a starting point and verify imports/types against the current Harness checkout. For an installable package, read references/config-packaging.md before generating manifests.
Before finalizing code
Check these failure-prone points:
- Is the intended Cordis shape correct: function plugin, service, event extension, child composition, or tool?
- Does every required
ctx.<service>have a matchinginject? - Is declaration merging being mistaken for runtime registration?
- Does the plugin load and unload safely under HMR?
- Are explicit external resources disposed?
- Are child plugins mounted with lifecycle ownership rather than manually called?
- Are config defaults and validation in the schema rather than scattered in runtime code?
- Does a tool return the value promised by
output.schema? - Does the tool separate canonical data from rendered prose?
- Does foreground work honor cancellation?
- Does every waterfall handler either deliberately short-circuit or call
next()? - Does a patch override the intended row
id, and if so, does it restate the complete config? - If packaged, does
package.jsondeclaredsh.bundle.patchand include the shipped patch/code files? - If installed from Git, are built artifacts available or is a safe
preparepath documented?
Currentness rule
DeepSeek Harness and its vendored Cordis surface evolve quickly. When exact signatures, service names, event modes/signatures, config fields, Fiber APIs, or package entry points matter, inspect the current repository or current official docs instead of extrapolating from this skill. Use references/sources.md as the starting source map.





