green-dalii/dsh-plugin-dev-skill

任意のエージェントが DeepSeek Harness(DSH)プラグインを正しく、効率的に、公式規約に従って開発できるようにするスキルパック。

dsh-plugin-dev-skill とは?

このスキルは、DeepSeek Harness(DSH)プラグイン開発のための包括的なガイドです。DSHがCordisフレームワーク上に構築されたプラグインシステムであるという心像モデルを提示し、可逆エフェクト、リアクティブコエフェクト、Fiberといった中核概念を説明します。Iron Law(鉄則)として、すべての登録はctxを通じて行い、依存関係はinjectで宣言し、設定はSchemasteryで検証可能にし、コールバックは純関数として実装することを要求します。ツール(Tool)開発、LLMアダプター実装、サービスと依存関係の管理、イベントシステムの利用、プラグインのパッケージ化とインストールに至るまで、テンプレートコードと段階的な手順を提供します。このスキルは、Claude CodeやCoderなどのAIエージェントがDSHプラグインを開発する際の操作マニュアルとして機能し、Referencesディレクトリに補足文書へのリンクを含みます。

対応✓Claude Code✓Codex CLI~Cursor
npx skills add green-dalii/dsh-plugin-dev-skill

Installed? Explore more 生産性&コラボレーション skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

DeepSeek Harness Plugin Dev Skill

任意のエージェントが DeepSeek Harness(DSH)プラグインを正しく、効率的に、公式規約に従って開発できるようにします。 本スキルは DSH プラグイン開発の操作マニュアルです。最初に心像モデルと鉄則を示し、次に直接コピーできるコードテンプレートと段階的な手順、最後に検証チェックリストを提供します。詳細な背景については References/ ディレクトリ内の要約ドキュメントを参照してください。


0. 本スキルを使用するタイミング

以下のいずれかのタスクが含まれる場合、必ず本スキルをロードしてください:

  • DeepSeek Harness 用のプラグイン(tool、LLM adapter、サービスプロバイダ、フック、UI、プロトコルブリッジなど)を作成、修正、またはデバッグする
  • cordis.yml / cordis.patch.yml / dsh.profile / dsh.bundle 設定を作成または修正する
  • dsh plugin ... を使用してプラグインをインストール、削除、パッケージ化する
  • DSH の ctx.tools、ctx.llm、ctx.agents、ctx.sessions などのサービス、または tools/*、agent/*、session/event などのイベントを理解する
  • DSH のプラグインモデル(Cordis フレームワーク)の仕組みを調査する

まず本 SKILL.md 全体を読んでから着手してください。着手する前に、プロジェクト内の既存の cordis.yml / profile / 関連ソースコードを読み、既存の規約を確認してください。


1. 心像モデル:DSH は Cordis 上に構築されたプラグインシステム

一言で言うと:DeepSeek Harness は Agent Harness SDK であり、そのすべての機能(ツール、LLM アダプター、ファイルアクセス、エージェントループ自体)はプラグイン(コンポーネント)であり、共有コンテキスト(context)にマウントされます。

3つの中核概念(論文「A Programming Paradigm for Spatiotemporal Composability」より。References/10-spatiotemporal.md 参照):

概念意味コードでの表現
可逆エフェクト(revertible effect)コンポーネントが共有環境に行う変更はすべて逆操作を伴い、実行時に追跡され、コンポーネントがアンロードされる際に LIFO 順序で元に戻されますctx.effect(() => () => cleanup);ctx.on()、ctx.tools.register() などはすべてエフェクトであり、アンロード時に自動的に元に戻されます
リアクティブコエフェクト(reactive coeffect)コンポーネントが依存するサービスを宣言します。サービスが出現/消失/実装変更されると、コンポーネントは自動的にアクティブ化/非アクティブ化/リロードされますexport const inject = ['tools'];依存関係がなくなるとプラグインは自動的に dispose され、復旧すると自動的にリロードされます
Fiber(コンポーネントインスタンス)ロードされた各プラグインインスタンスは fiber であり、ライフサイクルステートマシンを持ちますPENDING → LOADING → ACTIVE → UNLOADING → DISPOSED(apply がエラーをスローした場合は FAILED)

これにより導き出される鉄則:

  1. すべての登録は ctx を通じて行う必要があります(ctx.on / ctx.tools.register / ctx.effect / ctx.plugin / ctx.provide)。ctx を通じた登録はアンロード時に自動的にクリーンアップされます。手動で removeListener / clearInterval を行わないでください。
  2. ctx によって管理されないリソース(ネットワーク接続、独自タイマー、ファイルハンドル、watcher)は、すべて ctx.effect(() => { ...; return () => cleanup }) 内にラップする必要があります。
  3. 依存関係は宣言する必要があります(inject)。ctx.get() で必須の依存関係をプローブしたり、ロード順序を推測したりしないでください。順序は依存関係によって決定され、cordis.yml の行順序では決定されません。
  4. 設定は設定可能でなければなりません。デプロイ環境によって値が異なる可能性のあるパラメータは、すべて Config フィールドにする必要があります。ハードコーディングは絶対に避けてください(検証基準:cordis.yml で値を変更するだけでコードを変更せずに済むか?)。
  5. 設定エラーは明確に伝える必要があります。Schemastery スキーマを使用してロード時に検証し、無効な設定の場合はロードに失敗し、明確なエラーメッセージを表示します。問題のある状態で実行を継続しないでください。
  6. コールバックはリプレイ/ホットリロード可能である必要があります。表示系コールバック(output.render、presentCall、presentResult)は純関数でなければなりません。プラグインはいつでも HMR によってアンロード/リロードされる可能性があるため、リロードをまたいだグローバル状態に依存しないでください。

2. 環境とツールチェーン

  • プラグインは TypeScript モジュール(JS も可)であり、Node.js ESM 環境で実行されます。
  • コア依存パッケージ(すべて @deepseek-ai スコープ):
    • @deepseek-ai/cordis — プラグインフレームワーク(context、fiber、イベント、レジストリ)
    • @deepseek-ai/schemastery — 設定スキーマ検証(Standard Schema 実装)
    • @deepseek-ai/dsh-tools — defineTool とツールレジストリサービス
    • @deepseek-ai/dsh-llm — LlmAdapter、StreamChunk、GenerateOptions、CallId
    • 各機能シームパッケージ:dsh-shell、dsh-session、dsh-agent、dsh-system-prompt、dsh-fs、dsh-jobs、dsh-credentials など(完全なリストは References/08-capability-layering.md を参照)
  • 2つの開発エントリポイント(どちらかを選択):
    • ソースコードのチェックアウト(推奨、チュートリアルシナリオ):deepseek-ai/deepseek-harness をクローン、pnpm install、pnpm dsh web --patch <あなたのcordis.yml> で Web UI を起動、node --import tsx ../../vendor/cordis/bin.js で純粋な Cordis チュートリアルサンプルを実行。
    • インストール済み CLI:dsh --profile <name> ... でプロファイルを起動、dsh plugin --profile <name> <pnpm args> でプラグインを管理。

3. プラグインの最小形態(まずこれを覚える)

プラグインとは、apply 関数をエクスポートするモジュールです:

import type { Context } from '@deepseek-ai/cordis'

export const name = 'my-plugin'   // オプション、診断表示用のみ

export function apply(ctx: Context) {
  // ここで機能を登録
}

cordis.yml またはパッチを介してマウント:

- name: './src/my-plugin.ts'        # 相対パス(ソースコード/開発)または npm パッケージ名(インストール後)
  id: my-plugin                     # 安定した識別子、ローダーが id で設定を照合

3つのプラグイン形態

  1. 関数形態(デフォルト推奨):
    export const name = 'greet-tool'
    export const inject = ['tools']
    export function apply(ctx: Context) { /* ... */ }
    
  2. オブジェクト形態:export default { name, inject, apply(ctx) {} }
  3. クラス形態(外部にサービスを提供する必要がある場合):export default class MyService extends Service { constructor(ctx) { super(ctx, 'myService') } }

サービスを提供する必要が出るまでは、常に関数形態を使用してください。


4. Tool の開発(最も頻度の高いタスク)

ツールは ctx.tools に登録し、defineTool で定義します。テンプレート(直接コピー可能):

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'my-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'my_tool',                                  // モデルが見るツール名(snake_case の慣例)
    description: 'One sentence about what it does.',  // モデルが見る機能説明。具体的で、いつ使うかを明確に
    parameters: {
      path: { type: 'string', required: true, description: 'パラメータの意味' },
      limit: { type: 'number' },                      // required がない場合はオプション
    },
    output: {
      schema: { type: 'string' },                     // execute が返す規範的な JSON 値を宣言
      render: (_args, value) => [{ type: 'text', text: value }],  // モデルが見えるコンテンツに変換
    },
    async execute(args, exec) {
      // args はスキーマで検証され、型が推論されています
      // exec.signal はキャンセルシグナルです。長時間タスクはこれに応答する必要があります
      return `result for ${args.path}`
    },
  }))
}

defineTool の完全な契約(必ず遵守すること)

  • parameters:パラメータスキーママッピング。ルートは暗黙的にオープンなオブジェクト。各プロパティは required: true にできます。string/number/integer/boolean/null/array/object/oneOf をサポート。明示的な object ノードは additionalProperties: true | false を宣言する必要があります。
  • output.schema:execute が返す規範的な JSON 値(オブジェクト/配列/スカラー/null のいずれでも可)を宣言します。これはプログラムによる呼び出し元(Code Mode の await tools.xxx())向けの API であり、ハンドルとフィールドを直接返すように設計します。人間向けの説明は output.render に記述します。
  • execute(args, exec):
    • args は実行時に検証済みですが、スキーマ DSL で表現できない制約(空でない文字列、正の数、フィールド間の依存関係)は、自分で throw new Error(...) してください。
    • output.schema で宣言された規範的な値を返します。コンテンツブロックを返さないでください。 呼び出し元に自然言語から ID を解析させることを強要しないでください。
    • exec.signal を遵守する:シグナルがトリガーされたら進行中の作業をキャンセルします。
    • インフラストラクチャの障害(例外/無効な戻り値)→ 結果は isError としてマークされます。成功したが結果が理想的でない場合(例:ゼロ以外の終了コード)→ 規範的な値を返し、render 内で説明します。
  • output.render(args, value):純関数。規範的な値を ContentBlock[](モデルが見るテキスト)に変換します。ここで I/O やセッション状態の読み取りを絶対に行わないでください。
  • オプション output.presentationMeta(args, value):規範的な値からリプレイ可能な UI メタデータを派生します(純関数)。
  • オプション presentCall(args) / presentResult(args, result):UI でのツールのカードレンダリング意図(card: 'generic' | 'terminal' | 'diff' | 'search' | 'web' | 'read')を宣言します。純関数である必要があります(リアルタイムストリームとセッションリプレイの両方で実行されます)。I/O は行わないでください。
  • timeoutMs、isConcurrencySafe、finalizeContent などのランタイムメタデータをモデルから見えるスキーマとして扱わないでください。これらはモデルに漏洩しません。
  • パラメータは不変:args は読み取り専用として扱います。登録後にスキーマを変更したり、コールバックを置き換えたりしないでください。

長時間実行タスク(バックグラウンドタスク)

run_in_background をサポートする場合:

const jobs = ctx.get('jobs')
if (!jobs) throw new Error('background jobs unavailable: load @deepseek-ai/dsh-jobs')
return {
  kind: 'background',
  jobId: jobs.start({
    kind: 'my-work',
    label: args.command,
    ...exec.agent ? { owner: exec.agent } : {},
    run: () => { /* { cancel, done, readOutput? } を返す */ },
  }),
}

ポイント:jobId を発行した後は、タスク独自のキャンセルシグナル(job_kill / owner dispose が管理)を使用し、exec.signal は使用しません。成功出力スキーマは、{ kind: 'background', jobId } のような規範的なハンドルを保持できる必要があります。References/03-tools.md と @deepseek-ai/dsh-tool-bash の実装を参照してください。

ツールの実行戦略(拡張ポイント、必要に応じて使用)

拡張ポイントモード用途
tools/pre-executewaterfall許可/拒否/確認の戦略(権限ゲート);{kind:'allow'} / {kind:'deny',reason} / {kind:'ask'} を返す
ctx.tools.guard()単調ガード最終的な拒否。後続のリスナーは取り消せない(理由を返す = 拒否)
tools/executewaterfallディスパッチのラップ:タイムアウト/リトライ/メトリクス。exec.signal を置き換えられるが、削除は不可
tools/post-executewaterfallコンテンツ/値の置換、結果のブロック、モデルコンテキストの追加
tools/resultemit不変の最終結果の読み取り専用監視(ログ、監査)

戦略をツールに組み込まないでください。デプロイ戦略はフックプラグイン(通常の Cordis プラグインでこれらのイベントをリッスンするだけ。権限ゲートの例は References/11-cookbook.md を参照)に入れてください。


5. プラグイン設定(Schemastery)

プラグインは Config(同名の TS インターフェース + Schemastery スキーマ)をエクスポートします。Cordis は apply の前に検証し、デフォルト値を入力します:

import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'

export interface Config {
  greeting: string
  maxRetries: number
  verbose?: boolean
}

export const Config: Schema<Config> = Schema.object({
  greeting: Schema.string().default('Hello'),
  maxRetries: Schema.number().default(3),
  verbose: Schema.boolean().default(false),
})

export function apply(ctx: Context, config: Config) {
  // config は完全で検証済みであることが保証されています
}

cordis.yml で設定を渡す:

- name: './src/my-plugin.ts'
  config:
    greeting: 'Hi there'
    maxRetries: 5

ポイント:

  • Config は Standard Schema オブジェクトである必要があります(Schemastery で構築)。通常のオブジェクトをエクスポートしないでください。
  • よく使うコンストラクタ:Schema.string().required() / .default(x)、Schema.number()、Schema.boolean()、Schema.array(String)、Schema.union(['a','b'])、Schema.object({...}) のネスト。
  • !!js 式はロード時に評価されます(例:greeting: !!js process.env.GREETING ?? 'Hello')。!!js は config と disabled フィールドに対してのみ有効です。
  • 設定変更は HMR をトリガーします:古いインスタンスのアンロード(登録の自動クリーンアップ)→ 新しいインスタンスのロード。プラグインの外部で設定をキャッシュしないでください。

6. サービスと依存関係(サーバーサイド開発)

サービスの使用(消費者側)

export const inject = ['tools']        // 必須の依存関係:満たされない場合はロードされない
export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)        // apply 時には準備ができていることが保証されている
}

オプションの依存関係:inject を書かず、使用時に ctx.get('service') でプローブする(undefined が返る場合はプロバイダがないことを示す)。

サービスの提供(プロバイダ側)

Service のサブクラス(クラス形態プラグイン)を使用:

import { Service, type Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
  interface Context {
    metrics: MetricsService     // 宣言マージ:ctx.metrics に型を付与
  }
}

export default class MetricsService extends Service {
  static inject = ['llm']       // サービスも他のサービスに依存できる
  constructor(ctx: Context) {
    super(ctx, 'metrics')       // 'metrics' がサービス名
  }
  record(event: string, value: number) { /* ... */ }
}

export const name = 'metrics'
export function apply(ctx: Context) {
  ctx.plugin(MetricsService)
}

低レベル API(あまり使わないが知っておくべき):ctx.provide(name, value) でサービス実装を登録(エフェクト、アンロード時に自動登録解除)、ctx.set/get でストレージを読み書き、ctx.accessor で計算プロパティを定義、ctx.mixin でサービスメンバーを ctx にマウント。

サービスの動作セマンティクス(理解、暗記は不要)

  • inject は一度きりの起動チェックではない:実行中に必須サービスが消えると、依存するプラグインは自動的に dispose される。サービスが復旧すると、自動的にリロードされる。これにより、消費者はアンロードされたサービスへの参照を決して保持しないことが保証される。
  • サービス名はフラットなグローバル名前空間:tools、llm などは既に使用済み。独自のサービス名には識別可能なプレフィックスを付けること(例:myCap、metrics)。
  • サービスの分離:cordis.yml で group + isolate を使用すると、異なるプラグイングループが同じサービス名の異なるインスタンスを見ることができる(例:異なるタイムアウト設定の shell プロバイダを各グループが持つ)。

7. イベントシステム(プラグイン間通信)

ディスパッチモード(イベント名の一部。正しく選択する必要がある)

モード呼び出しセマンティクス
emitctx.emit(name, ...args)同報。待機せず、戻り値を収集しない
parallelawait ctx.parallel(...)すべてのリスナーが並行して実行され、完了を待つ
serialawait ctx.serial(...)順次実行。最初に null/false/undefined 以外の値を返したリスナーが勝ち、停止する
bailctx.bail(...)serial の同期版
waterfallawait ctx.waterfall(name, ...args, next)ラップするミドルウェア。リスナーは next を受け取り、下流の戻り値をラップする

waterfall の鉄則:観察/アノテーションのみを行うリスナーは next() を呼び出す必要があります。next() を呼び出さずに直接戻り値を返す = 意図的なショートサーキット(拒否/インターセプト)。 next() の呼び出しを忘れると、下流のデフォルトの動作が黙って飲み込まれます。

型安全なイベント

declare module '@deepseek-ai/cordis' {
  interface Events {
    'my-plugin/ready': (payload: { id: string }) => void
    'my-plugin/check': (input: string) => boolean | undefined
  }
}

イベント命名規則 namespace/action(例:agent/step、tools/result、session/event)。リスナーは ctx.on() で登録すると、プラグインのアンロードに伴って自動的にクリーンアップされます。

よく使われる Harness イベント(開発時に頻出)

  • tools/pre-execute / tools/execute / tools/post-execute / tools/result — ツールパイプライン(上表参照)
  • agent/*(agent/request、agent/pre-step、agent/session-start、agent/turn-stopping など)— エージェントのライフサイクルとリクエスト構築
  • session/event — 永続化されたセッションイベントストリーム(turn/*、step/*、tool/call、tool/result、assistant/chunk はすべてここの event.type であり、同名の Cordis イベントではありません)
  • approval/request — 承認 waterfall
  • system-prompt/assemble — システムプロンプト全体のアセンブル(権威ある戻り値。リスナーは既存の貢献を保持する責任があります)

完全なシグネチャ/トリガーモードは、各サブシステムのページで生成される cordis-surface ブロックを参照してください(References/08-capability-layering.md にガイドがあります)。


8. LLM アダプター(新しいモデルプロバイダーへの接続)

アダプター = LlmAdapter を継承し、stream() を実装するクラス。Harness のプロバイダーに依存しないリクエストを特定の API 呼び出しに変換し、StreamChunk フラグメントに変換して返します。

import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
import { LlmAdapter, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm'

class MyAdapter extends LlmAdapter {
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
    // 1. options.messages → プロバイダーの形式
    // 2. ストリーミング API を呼び出す(必ず options.signal を渡す)
    // 3. レスポンス → StreamChunk のシーケンス
  }
}

export const name = 'my-llm-adapter'
export const inject = ['llm']
export const Config = Schema.object({
  apiKey: Schema.string().required(),
  providers: Schema.array(String).required(),
})

export function apply(ctx: Context, config: Config) {
  ctx.llm.registerAdapter(config.providers, new MyAdapter(config.apiKey))
}

StreamChunk プロトコル(厳守すること)

async function* chunks(): AsyncIterable<StreamChunk> {
  yield { type: 'block-start', index: 0, blockType: 'text' }
  yield { type: 'text-delta', index: 0, text: 'Hello' }
  yield { type: 'block-end', index: 0, block: { type: 'text', text: 'Hello world' } }
  // ツール呼び出しブロック:
  yield { type: 'block-start', index: 1, blockType: 'tool-call' }
  yield { type: 'tool-call-delta', index: 1, id: CallId('c1'), name: 'bash', argumentsDelta: '{"command":"ls"}' }
  yield { type: 'block-end', index: 1, block: { type: 'tool-call', id: CallId('c1'), name: 'bash', arguments: '{"command":"ls"}' } }
  yield { type: 'usage', usage: { inputTokens: 100, outputTokens: 50 } }   // finish の前に必須
  yield { type: 'finish', reason: { kind: 'stop' } }                        // 最後である必要がある
}

ルール:各 block-start には対応する block-end が必要。index は 0 からインクリメント。tool-call の arguments は常に生の JSON 文字列。finish は最後のチャンク。usage は finish の前。

エラーとメタデータ

  • トランスポート/プロトコル障害:throw new LlmError(msg, 'STABLE_CODE')(安定したコード付き)。通常の Error の自動変換に依存しないでください。
  • プロバイダーが GenerateOptions の特定のフィールドをサポートしていない場合:throw new LlmError(..., 'UNSUPPORTED')。黙って無視しないでください。
  • 各 HTTP リクエストに attributionHeaders() をマージし、options.signal を渡します。
  • オプション:resolveModel()(プロバイダー/モデルの識別情報 + オプションの context/reasoning メタデータを返す)と listModels()(モデルオプションを公開する)をオーバーライドします。

完全なチュートリアルは References/05-llm-adapter.md を参照。参考実装:packages/llm/llm-deepseek(OpenAI 互換 SSE)と packages/llm/llm-pi-ai。


9. 機能の階層化(3つのロール、交換可能な機能のデザインパターン)

機能に交換可能なプロバイダー(例:Bash 実行)が必要な場合、3つのロールに分割し、異なるパッケージに配置します:

  1. Service Definition(例:dsh-shell):Cordis サービスインターフェース + Request/Result 型を定義。abstract class MyCapService extends Service { super(ctx,'myCap'); abstract execute(req): Promise<res> }
  2. Service Provider(例:dsh-bash-local):インターフェースを実装。class MyCapLocal extends MyCapService { ... };apply(ctx){ ctx.plugin(MyCapLocal) }
  3. Consumer(例:dsh-tool-bash):機能をモデルツールとして公開。inject: ['tools','myCap']

依存の方向:Provider は Definition に依存。Consumer は Definition に依存。Provider と Consumer は互いに依存しません。プロバイダーの変更は cordis.yml の1行を変更するだけで済み、Definition と Consumer は変更不要です。

予防的に分割しないでください。ロールが独立して進化する必要がある場合にのみ分割してください。単純なツールプラグインは1つのパッケージで十分です。


10. パッケージ化とインストール(プラグインをユーザーに届ける)

2つの概念

  • コンビネーションパッケージ(bundle):設定レイヤーを同梱した npm パッケージ。マニフェストは dsh.bundle を宣言します。これを作成して配布します。
  • プロファイル(profile):$DSH_HOME/profiles/<name> に配置される起動可能な組み合わせ。マニフェストは dsh.profile を宣言します(順序付けられた bundles リストを含む)。ユーザーが起動するものです。

コンビネーションパッケージのパッケージ化

hello-plugin/
├── package.json       # dsh.bundle を宣言
├── cordis.patch.yml   # レイヤーコンテンツ
└── index.js           # プラグインモジュール
// package.json
{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "type": "module",
  "main": "index.js",
  "files": ["index.js", "cordis.patch.yml"],
  "dsh": { "bundle": { "patch": "cordis.patch.yml" } }
}

cordis.patch.yml 内で、バンドル自身のプラグインリストを宣言します:

to: base
patches:
  - op: add
    path: /plugins/-
    value:
      name: './index.js'
      id: hello
      config: { greeting: 'Hello from bundle!' }

ユーザーがバンドルをインストールすると、DSH は dsh.bundle.patch のパッチをベース設定に適用します。

プロファイルとバンドルの管理

  • dsh plugin add <npmパッケージ> — バンドルをインストール
  • dsh plugin remove <npmパッケージ> — バンドルをアンインストール
  • dsh plugin pack <source> — バンドルを tgz にパッケージ化
  • dsh --profile <name> web — プロファイルの Web UI を起動

プロファイルはスタンドアロンの Cordis アプリケーションです。dsh --profile <name> shell はそのコンテキスト内でシェルを起動します。

バンドルとプロファイルの完全なリファレンスについては、References/12-bundles.md を参照してください。


11. 検証リスト(コミット前のチェック)

プラグインをコミットする前に、以下のすべての項目を確認してください:

  • すべての登録は ctx を通じて行われていますか? 手動の cleanup/removeListener はありませんか?
  • ctx.effect 外で管理されているリソースはありませんか?(タイマー、wathcher、ネットワーク接続など)
  • 依存関係は inject で宣言されていますか? ロード順序の仮定はありませんか?
  • すべての可変設定は Config にありますか? ハードコードされた環境固有の値はありませんか?
  • Config は Schemastery スキーマを使用していますか? ロード時の検証は行っていますか?
  • すべての長時間実行操作は exec.signal に応答していますか?(バックグラウンドジョブは別)
  • defineTool の execute は規範的な値を返していますか? 自然言語の説明を返していませんか?
  • presentCall / presentResult は純関数ですか? 副作用や I/O はありませんか?
  • LLM アダプターは finish、usage、エラーのあるコードを正しく生成していますか?
  • waterfall イベントハンドラーは適切に next() を呼び出していますか? 誤ったショートサーキットはありませんか?
  • エラーメッセージは明確で実用的ですか? ユーザーは何を修正すべきか分かりますか?
  • パッケージマニフェストは正しい dsh.bundle を宣言していますか?
  • コードは既存のプロジェクトのスタイルと命名規則に従っていますか?

References

このスキルで参照されている文書へのリンク(References/ ディレクトリ内):

  • 01-quickstart.md — クイックスタート:最初のプラグイン
  • 03-tools.md — ツール:完全な defineTool 契約
  • 05-llm-adapter.md — LLM アダプターの完全な実装ガイド
  • 06-configuration.md — 設定:Schemastery の詳細
  • 07-events.md — イベント:完全なディスパッチモードのリファレンス
  • 08-capability-layering.md — 機能の階層化:3つのロールパターンとシームパッケージの完全なリスト
  • 09-services.md — サービス:サービスの提供と消費の詳細
  • 10-spatiotemporal.md — 時空間構成可能性:論文要約
  • 11-cookbook.md — クックブック:一般的なパターン(権限、メトリクスなど)
  • 12-bundles.md — バンドルとプロファイル:完全なリファレンス

関連スキル