Community寫作與編輯github.com

TrueHOOHA/dsh-plugin-dev-skill

AI Skill for developing DeepSeek Harness (dsh) plugins — Cordis-based agent framework. 辅助开发 dsh 插件的 AI 技能,覆盖 tool、service、LLM adapter、event listener 等能力的创建与发布。

dsh-plugin-dev-skill 是什麼?

dsh-plugin-dev-skill is a Claude Code agent skill that aI Skill for developing DeepSeek Harness (dsh) plugins — Cordis-based agent framework. 辅助开发 dsh 插件的 AI 技能,覆盖 tool、service、LLM adapter、event listener 等能力的创建与发布。.

相容平台~Claude Code~Codex CLI~Cursor
npx skills add TrueHOOHA/dsh-plugin-dev-skill

Installed? Explore more 寫作與編輯 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

dsh Plugin Development

Develop plugins for DeepSeek Harness (dsh), a Cordis-based agent framework. Plugins are TypeScript modules exporting apply(ctx: Context), composed via cordis.yml.

Quick Reference

Plugin Structure

import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export function apply(ctx: Context) { /* register capabilities */ }

Three forms: function (default), object ({ name, inject, apply }), class (extends Service — use only when providing a service to other plugins).

Dependencies: export const inject = ['tools', 'llm'] — framework keeps plugin PENDING until all injected services are ready.

Auto-cleanup: Everything registered through ctx is an effect — unload automatically cleans up. For custom resources (timers, connections), wrap in ctx.effect(() => { ... return () => cleanup }).

Child plugins: const fiber = ctx.plugin(childPlugin) — children inherit parent context; await fiber.dispose() unloads recursively.

Fiber States

PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
                 ↘ FAILED

PENDING → missing service dependency. FAILED → apply threw or config validation failed. Service disappearing at runtime auto-disposes dependents.

Tools

import { defineTool } from '@deepseek-ai/dsh-tools'
export const inject = ['tools']
export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet', description: '...',
    parameters: { name: { type: 'string', required: true } },
    output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }] },
    async execute(args) { return `Hello, ${args.name}!` },
  }))
}

defineTool converts parameters to JSON Schema, validates args, and auto-unregisters on unload. See references/basic/tool.md for details.

Configuration

import Schema from '@deepseek-ai/schemastery'
export interface Config { greeting: string; maxRetries: number }
export const Config: Schema<Config> = Schema.object({
  greeting: Schema.string().default('Hello'),
  maxRetries: Schema.number().default(3),
})
export function apply(ctx: Context, config: Config) { /* validated config */ }

Must export BOTH interface Config AND const Config: Schema<Config>. Invalid config → FAILED state with clear error. Use !!js in YAML for dynamic values: config: { apiKey: !!js process.env.API_KEY }. See references/basic/config.md.

Services

Provide: class extends Service { constructor(ctx) { super(ctx, 'name') } }

  • declare module '@deepseek-ai/cordis' { interface Context { name: NameService } }

Consume: export const inject = ['name'] → ctx.name.method().

Optional: ctx.get('name') → returns undefined when absent.

Service isolation: group: true + isolate: { shell: true } gives each group its own provider instance. See references/framework/service.md.

Events

ModeCallUse
emitctx.emit(n, ...args)Sync broadcast, ignore returns
parallelawait ctx.parallel(n, ...args)Concurrent listeners
serialawait ctx.serial(n, ...args)Sequential, first non-null wins
bailctx.bail(n, ...args)Sync serial
waterfallctx.waterfall(n, ...args, next)Middleware chain

Waterfall listeners must call next() unless intentionally short-circuiting. Key harness events: agent/step, tools/result, session/event. See references/framework/events.md.

LLM Adapters

class MyAdapter extends LlmAdapter {
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
    // Convert → provider API → yield StreamChunk
  }
}
ctx.llm.registerAdapter(['my-provider'], adapter)

StreamChunk order per block: block-start → text-delta/tool-call-delta → block-end → usage → finish. Throw LlmError with stable codes. See references/practice/llm-adapter.md.

Three-Layer Capability Design

Definition (Service abstract class) → Provider (implements) → Consumer (tool)

All three share the same service name via inject. Only split into separate packages when roles need independent evolution. See references/practice/index.md.

cordis.yml / Bundles

Local dev: --patch ./cordis.patch.yml

- insert:
    - id: my-plugin
      name: '/absolute/path/to/src/my-plugin.ts'
      config: { greeting: 'Hi' }

Distribution: npm package with dsh.bundle manifest + cordis.patch.yml. Install: dsh plugin --profile demo add ./hello-plugin. Layer order: profile bundles → profile patch → home patch → --patch overlays. Later layers win by row (no deep merge). See references/basic/publish.md.

HMR

Load @deepseek-ai/cordis-plugin-hmr + @deepseek-ai/cordis-plugin-logger-console

  • @deepseek-ai/cordis-plugin-timer to auto-reload on file save.

Diagnosing PENDING

import { FiberState, type Context } from '@deepseek-ai/cordis'
for (const fiber of ctx.registry.values().flatMap(r => r.fibers))
  if (fiber.state === FiberState.PENDING)
    console.log(`${fiber.name} is PENDING`)

Reference Docs

Detailed guides in the references/ directory:

PathCovers
references/basic/First plugin, tools, config, publishing
references/framework/Lifecycle, services, events
references/practice/Three-layer design, LLM adapters
references/cordis-tutorial/Step-by-step Cordis framework tutorial

相關技能