DSH プラグイン開発標準
このスキルは、DeepSeek Harness(DSH)プラグインを開発するための唯一の標準です。DSH公式ドキュメントのチュートリアル、リファレンスマニュアル、生成ディレクトリに分散している規約を、実行可能なワークフロー、ハードルール、チェックリストに集約します。DSHのすべてはプラグインです。モデルアダプタ、ツールレジストリ、セッションログ、エージェントループそのものも含まれます。したがって、このスキルに従うことは、DSH自身のアーキテクチャに沿って拡張することになります。
適用範囲
- リポジトリ内、ファイルベースのDSHプラグイン開発:プラグインパッケージの作成、
cordis.yml行の登録、パッチオーバーレイ、ツール開発、モデル接続、パッケージングとインストール。 - DSHモノレポ内のワークスペースパッケージ開発(
packages/<group>/<pkg>)もこのスキルの対象です(references/workspace-package.md)。 - このスキルはカバーしません:セッション内動的プラグイン(
cordis_define/cordis_runフロー)とエージェントプリセットの組み合わせ編集。これらは各デプロイメントの専用スキルまたは公式ツールがカバーします。
ハードルール(あらゆるシナリオで必ず遵守)
- インターフェースは生成リファレンスを基準とする。 サービス名、公開メソッド、イベントシグネチャ、
ctxキーは、リポジトリが自動生成するサブシステムページとTypeScriptインターフェースを基準とします。サービス名、サンプル、古いコードから完全なAPIを推測したり、別の静的なリストを保守したりしないでください。 - すべての貢献は副作用である。
ctxを介して行うすべての登録(イベントリスナー、ツール、アダプタ、ctx.effect)は、プラグインのアンロード時に自動的に取り消されます。モジュールスコープでプロセスレベルまたはページレベルの副作用を作成しないでください。disposerを返さないサードパーティのサブスクリプションについては、積極的にクリーンアップメカニズムを確認してください。 waterfallリスナーはnext()を呼び出さなければなりません。next()を呼び出さないことは、意図的に下流を短絡することを意味します(インターセプト/ゲートウェイ用)。オプションではありません。- 失敗は明確に。
applyが例外をスローするとプロセスは終了します。設定の検証に失敗した場合は、明確にエラーを報告してください。Schemaはそれ自身で完全な制約を表現する必要があり、実行時にエラーを静かに飲み込んではいけません。 - 必須の依存関係は
injectで宣言し、オプショナルな依存関係はctx.get()でnullチェックを行います。injectを使用してundefinedチェックを回避しないでください。また、宣言されていないctx.xxxに直接アクセスしないでください。宣言されていないサービスは、サービスリゾルバーで評価されたときにundefinedになる可能性があります。 - 設定は必ずSchemasteryを使用する。
interface Configと同名のSchemaをエクスポートし、デフォルト値はschemaに記述します。プレーンなオブジェクトをConfigとしてエクスポートしないでください。デプロイメントによって値が変わる可能性のあるパラメータはすべて設定に入れる必要があります。 - ツールの
executeは標準的なJSON値を返し、コンテンツブロックは返さない。 人間向けのテキストはoutput.renderに配置します。デプロイメント戦略/フックをツール本体に組み込まないでください。 - モデルに見えるものは即座に記録される。 モデルが見る新しい入力を追加するたびに、セッションログで再構築可能なメカニズム(新しい永続イベントまたは
agent.inject()経由)に配置し、実行時不変条件アサーションを持たせる必要があります。 - npm設定パネルでは
ctx.connection.rpcを優先する。 ブラウザ側の設定パネルがメインプロセスのメソッドを呼び出す場合は、優先的にConnection RPC(ctx.connection.rpc.handle+ctx.connection.rpc.call)を使用します。ボイラープレートはreferences/connection-rpc.mdを参照してください。生の@Remote、手書きのtypertマニフェスト、createRequireを使用したharnessソースコードへのフックは禁止です。完全なTypertジェネレーターの出力をpackage.jsonの./typert+./remoteエクスポートで公開し、ctx.remote.$mount()で消費するパスは引き続き有効です。
標準ワークフロー
シナリオA:新しいプラグインの作成
- プラグインが何に貢献するかを決定します(サービス?ツール?リスニング?)。
references/seams.mdの「新しい振る舞いの所属位置」テーブルを使用してメカニズムを選択します。 src/<name>.tsを作成し、name、inject(オプション)、apply(ctx, config?)をエクスポートします。最初は関数形式で記述します。外部にサービスを提供する必要がある場合は、Serviceクラス形式に変更します。- ローカル開発ループ(ソースコードチェックアウト):
mkdir -p scratch-plugin/src
# scratch-plugin/cordis.yml —— パッチオーバーレイ;プラグインパスは絶対パスである必要があります
- insert:
- id: hello
name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
pnpm dsh web --patch ./scratch-plugin/cordis.yml # http://127.0.0.1:3080 を開く
- ロードとアンロードを検証します:起動ログに表示されること、停止時にリソースが実際にクリーンアップされること(
references/plugin-anatomy.md)。
シナリオB:モデルにツールを追加する
inject: ['tools']を使用し、defineToolで定義します(name/description/parameters/output/execute)。references/tools.mdのexecute規約に従って実装します:SchemaDSLでパラメータと出力を宣言、executeは標準的な値を返す、exec.signalに従う、オプションでpresentationMeta/UIカード。- 戦略が必要な場合は、
tools/*イベント(pre-execute/guard/execute/post-execute/result)にフックし、戦略をツール本体にハードコードしないでください(権限ゲートの例はreferences/plugin-forms.mdを参照)。 - 再起動後にモデルに実際に呼び出させて検証します。
シナリオC:置換可能な能力(複数のプロバイダー)
references/three-roles.mdに従い、Definition / Provider / Consumerの3つのパッケージに分割します(必要に応じてロールを統合し、予防的な分割はしないでください)。- Definitionは
Request/Result型と抽象Serviceを持ちます。Providerは実装します。Consumerはツールまたはサービスのコンシューマーとして公開します。 cordis.ymlにはProvider行とConsumer行のみを記述します。プロバイダーの変更は1行の変更で済みます。
シナリオD:新しいモデルプロバイダーの接続
LlmAdapterを継承してstream()を実装し、StreamChunkプロトコルに従ってチャンクを出力します。エラーは安定したcodeを持つLlmErrorを使用するか(またはインバンドでfinish { kind: 'error' | 'aborted' }で終了します)。各HTTPリクエストでattributionHeaders()を統合し、signalを渡します。ctx.llm.registerAdapter(['<provider>'], adapter)を呼び出します。オプションでresolveModel()/listModels()をオーバーライドできます。- コンポジションで
agent-loopのprovider/modelを設定して検証します。詳細はreferences/llm-adapter.mdを参照してください(7つのプロトコル義務を含む)。
シナリオE:パッケージングとインストールの提供
- コンポジションパッケージを作成します:
package.jsonでdsh.bundleを宣言し(cordis.patch.ymlを指す)、パッチ行はパッケージ名でプラグインを参照します。インポート専用のライブラリパッケージはdsh.bundleを宣言しません。 - インストール:
dsh plugin --profile <name> add <pkg>。最初にdsh --profile <name> --dump-configでレイヤーを検証してから起動します。 - レイヤーの順序と行全体の置換セマンティクスを覚えておいてください(
references/packaging.md)。
シナリオF:DSHモノレポ内に新しいパッケージを作成する
references/workspace-package.mdのファイルごとのチェックリストに従って実行します:パッケージの作成(package.json不変条件/tsconfig/src/README)→ ルート設定への登録 → パッケージトポロジーと命名(ロール語彙表)→ README Model Experience構造 → 検証コマンド。
意思決定クイックリファレンス
| 私がしたいこと… | メカニズム | 詳細 |
|---|---|---|
| 他のプラグインに能力を公開する | Service(クラス形式) | references/services.md |
| 既存の能力を利用する | inject または ctx.get() | references/services.md |
| プラグイン間通信 / 拡張ポイント | ctx.on / ctx.emit などのイベント(5つのディスパッチモード) | references/events.md |
| ユーザーが設定可能にする | Config + Schemastery | references/config.md |
| モデルに能力を追加する | defineTool → ctx.tools.register(または生のJSON Schema) | references/tools.md |
| 新しいモデルプロバイダーに接続する | LlmAdapter + ctx.llm.registerAdapter | references/llm-adapter.md |
| 置換可能な能力を分割する | 3つのロール(Definition/Provider/Consumer) | references/three-roles.md |
| プラグインを配布する | コンポジションパッケージ + プロファイル | references/packaging.md |
| 組み込みサービス / 所属位置を調べる | seamディレクトリ、アーキテクチャマップ | references/seams.md |
| スコープ / サービスストレージ / Fiber API | ctx.extend/isolate/provide/mixin、fiber.* | references/context-api.md |
| フック / UI / パネル / プロトコルブリッジプラグイン | 5つの拡張形式 + 機能→メカニズムマッピング | references/plugin-forms.md |
| ブラウザ側パネルからメインプロセスサービスを呼び出す | ctx.connection.rpc.handle/call、エンドポイント + エンベロープ | references/connection-rpc.md |
| リポジトリ内に新しいパッケージを作成する / 命名する | ワークスペースパッケージリスト + ロール語彙表 | references/workspace-package.md |
完了前チェックリスト
- インターフェースを生成リファレンスで確認しました(サービス/イベント/ctxキーはすべて生成基準)。名前からAPIを推測していません。
- すべての登録は
ctx経由です(イベント/ツール/アダプタ/effect)。アンロード時にクリーンアップ可能です。順序に依存するクリーンアップは同じctx.effect内にあります。 - 必須の依存関係のインジェクトが正しく宣言されています。オプショナルな依存関係には
undefined処理があります。 - 設定のあるプラグイン:
ConfigはSchemasteryを使用、デフォルト値はschemaに記述、無効な設定はロード時に明確に失敗します。 - ツールがある場合:
executeは標準的なJSON値を返します。renderが人間可読性を担当します。戦略はtools/*イベント経由です。exec.signalに従います。isConcurrencySafeが宣言されています(宣言なし → exclusive)。 -
waterfallリスナーがある場合:next()を呼び出して返します(意図的な短絡の場合を除く)。 - LLMアダプタがある場合:
StreamChunkプロトコルが完全です(チャンクペアリング、indexは最初の出現時、usageはfinishの前、argumentsは全体が生のJSON文字列)。エラーは2つの有効なパスのいずれかを通ります。サポートされていないフィールドはUNSUPPORTEDをスローします。ネイティブリプレイが必要な場合はfinish.replayStateを送信します。attributionHeadersとsignalを渡します。 - コンポジション行とレイヤー順序が正しいです。新しい行は
--dump-configで表示されます。HMR/再起動後も残留登録がありません。 - モデルが見るコンテンツが変更された場合:ログで再構築可能なメカニズム内にあります。
- ブラウザ側設定パネル:
ctx.connection.rpc.handle/callを優先。生の@Remote、手書きのtypertマニフェスト、createRequireを使用したharnessソースコードへのフックは禁止。完全なTypertジェネレーター +./typert+./remote成果物は引き続き有効。 - 新しいワークスペースパッケージ:
package.json不変条件、1つのaggregateだけ、名前がロール語彙表に準拠、READMEにModel Experience構造があり、constraints/typecheck/lint/build/hygieneがすべて緑色。
リファレンスファイル(必要に応じてロードし、一度にすべて読まないでください)
完全なインデックスと「いつ読むか」の対応表は
references/README.mdを参照してください。
references/plugin-anatomy.md—— プラグインの作成/変更、ライフサイクル処理、またはHMR時に読むreferences/services.md—— サービスの定義/消費、依存関係のインジェクト時に読むreferences/events.md—— イベントを使用した通信、拡張ポイントのリスニング時に読むreferences/config.md—— プラグインを設定可能にする時に読むreferences/context-api.md—— スコープ、サービスストレージ、またはFiber APIを使用する時に読むreferences/three-roles.md—— 置換可能な能力を分割する時に読むreferences/tools.md—— モデルツールの開発時に読むreferences/llm-adapter.md—— 新しいモデルプロバイダーに接続する時に読むreferences/plugin-forms.md—— フック/UI/プロトコルブリッジプラグインを作成する時に読むreferences/connection-rpc.md—— npm設定パネルがメインプロセスのメソッドを呼び出す必要がある時に読む。生の@Remote/手書きマニフェスト/createRequireソースブリッジに遭遇した時にも読むreferences/packaging.md—— パッケージング、インストール、プラグインの提供時に読むreferences/workspace-package.md—— モノレポ内に新しいパッケージを作成する時に読むreferences/seams.md—— 組み込みサービス、所属位置、またはアーキテクチャマップを調べる時に読む
検証
- フォーマット自己チェック:
nameがkebab-caseでディレクトリ名と一致していること。descriptionが空でなく簡潔であること(このスキルは500文字以内)。本文は標準的なMarkdownを使用。参照しているすべてのreferencesファイルが実際に存在すること。 - ディレクトリ命名:このスキル名(
name)はdsh-plugin-devであり、ホストリポジトリ名dsh-plugin-dev-skillsとは異なります。クローン/解凍後は、フォルダ名をdsh-plugin-dev(nameと一致)にする必要があります。そうしないと、ディレクトリ名でアドレス指定するローダーがこのスキルを発見できない可能性があります。 skills-refCLIがある環境では、skills-ref validate ./dsh-plugin-devを実行できます。- リグレッショントリガー:
descriptionを変更した後、evals/trigger-queries.json評価セットを実行します(方法はリポジトリのevals/README.mdを参照)。 - 動作検証:シナリオAに従って最小限のプラグインを完了します(ロードログ + アンロードクリーンアップ)。次に、シナリオBに従って
greetツールを完了します。