DSH Plugin-Entwicklungsstandard
Diese Skill ist der verbindliche Standard für die Entwicklung von DeepSeek Harness (DSH) Plugins: Sie fasst die in der offiziellen DSH-Dokumentation verstreuten Konventionen – aus Tutorials, Referenzhandbüchern und Generierungsverzeichnissen – zu ausführbaren Workflows, harten Regeln und einer Checkliste zusammen. In DSH ist alles ein Plugin – Modelladapter, Werkzeugregister, Sitzungslogs, selbst der Agent-Loop – daher bedeutet die Befolgung dieser Skill, DSH auf seine eigene architektonische Art zu erweitern.
Anwendungsbereich
- Dateibasierte DSH-Plugin-Entwicklung im Repository: Plugin-Pakete schreiben, cordis.yml-Zeilen registrieren, Patch-Overlays anwenden, Werkzeuge entwickeln, Modelle anbinden, Pakete schnüren und installieren.
- Die Entwicklung von Workspace-Paketen im DSH-Monorepo (packages//) fällt ebenfalls unter diese Skill (references/workspace-package.md).
- Diese Skill deckt nicht ab: Dynamische Plugins innerhalb von Sitzungen (cordis_define/cordis_run-Flows) und die Bearbeitung von Agent-Preset-Kombinationen – diese werden von jeweils spezialisierten Skills oder offiziellen Werkzeugen behandelt.
Harte Regeln (in jedem Szenario zwingend)
- Schnittstellen richten sich nach der generierten Referenz. Dienstnamen, öffentliche Methoden, Ereignissignaturen und Context-Keys richten sich nach den automatisch generierten Subsystem-Seiten und TypeScript-Schnittstellen des Repositorys; leite keine vollständige API aus Dienstnamen, Beispielen oder altem Code ab und pflege keine separate statische Liste.
- Alle Beiträge sind Nebenwirkungen. Jede über den Context registrierte Aktion (Ereignis-Listener, Werkzeuge, Adapter, ctx.effect) wird beim Deaktivieren des Plugins automatisch rückgängig gemacht; erstelle keine Prozess- oder Seitenebenen-Nebenwirkungen im Modul-Scope; kläre bei Drittanbieter-Abonnements ohne Disposer aktiv den Bereinigungsmechanismus.
- Waterfall-Listener MÜSSEN next() aufrufen. Ein fehlender next()-Aufruf bedeutet eine beabsichtigte Kurzschlussunterbrechung der nachgelagerten Listener (für Interception/Gateway) – kein optionales Verhalten.
- Fehler müssen laut sein. Ein apply()-Fehler beendet den Prozess; Konfigurationsvalidierungsfehler werden explizit gemeldet; Schemas sollten vollständige eigene Constraints ausdrücken, Fehler nicht still zur Laufzeit verschlucken.
- Erforderliche Abhängigkeiten mit inject deklarieren, optionale mit ctx.get() auf null prüfen. Verwende inject nicht, um undefined-Prüfungen zu umgehen; greife nicht direkt auf nicht deklarierte ctx.xxx zu – undeklarierte Dienste können durch den Service-Resolver undefined ergeben.
- Konfiguration IMMER mit Schemastery. Exportiere das Interface Config und ein gleichnamiges Schema; Standardwerte gehören ins Schema; exportiere kein normales Objekt als Config; alle Parameter, die in unterschiedlichen Deployments anders sein könnten, MÜSSEN in die Konfiguration.
- Werkzeug-execute gibt normierte JSON-Werte zurück, keine Inhaltsblöcke. Menschlich lesbarer Text kommt in output.render; Bereitstellungsstrategien/Hooks nicht in die Werkzeuglogik einbauen.
- Modellsichtbarkeit bedeutet bereits aufgezeichnet. Jede neue modellsichtbare Eingabe muss in einen Mechanismus fallen, der das Sitzungslog rekonstruieren kann (neues persistentes Ereignis oder über agent.inject()), mit einer Runtime-Invariant-Assertion.
- npm-Einstellungs-Panel bevorzugt
ctx.connection.rpc. Browser-Seitige Einstellungspanels rufen Hauptprozess-Methoden auf – bevorzugt über Connection RPC (ctx.connection.rpc.handle+ctx.connection.rpc.call), Vorlage in references/connection-rpc.md. Verboten: nacktes@Remote, händisches Typert-Manifest,createRequirezum Einhängen von Harness-Quellcode. Vollständige Typert-Generator-Ausgabe, die überpackage.json./typert+./remoteexportiert und vonctx.remote.$mount()konsumiert wird, ist weiterhin gültig.
Standard-Workflows
Szenario A: Ein neues Plugin erstellen
- Bestimme, was das Plugin beitragen soll (Dienst? Werkzeug? Listener?) und wähle den Mechanismus anhand der Tabelle „Neues Verhalten zuordnen“ in references/seams.md.
- Erstelle src/.ts und exportiere name, inject (optional), apply(ctx, config?). Schreibe zuerst die Funktionsform; wechsle zur Service-Klassenform, wenn ein Dienst nach außen bereitgestellt werden soll.
- Lokaler Entwicklungsdurchlauf (Source-Checkout):
mkdir -p scratch-plugin/src
# scratch-plugin/cordis.yml – Patch-Overlay; Plugin-Pfad MUSS absolut sein
- insert:
- id: hello
name: '/absoluter/pfad/zu/deepseek-harness/scratch-plugin/src/my-plugin.ts'
pnpm dsh web --patch ./scratch-plugin/cordis.yml # Öffne http://127.0.0.1:3080
- Überprüfe das Laden und Entladen: Start-Logs erscheinen, Ressourcen werden beim Deaktivieren bereinigt (references/plugin-anatomy.md).
Szenario B: Ein Werkzeug für ein Modell hinzufügen
- inject: ['tools'], mit defineTool definieren (name/description/parameters/output/execute).
- Implementiere nach den execute-Konventionen aus references/tools.md: Schema DSL deklariert Parameter und Ausgabe, execute gibt normierte Werte zurück, beachtet exec.signal, optional presentationMeta/UI-Cards.
- Bei Bedarf an Strategie: tools/*-Events (pre-execute/guard/execute/post-execute/result) verwenden, Strategie nicht in die Werkzeuglogik einbauen (Beispiel für Berechtigungs-Gate in references/plugin-forms.md).
- Nach Neustart durch tatsächlichen Modellaufruf verifizieren.
Szenario C: Austauschbare Fähigkeiten (mehrere Anbieter)
- Nach references/three-roles.md in drei Pakete aufteilen: Definition / Provider / Consumer (Rollen nach Bedarf zusammenlegen, keine vorbeugende Aufteilung).
- Definition besitzt Request/Result-Typen und abstrakten Service; Provider implementiert; Consumer stellt als Werkzeug oder Dienst-Nutzer bereit.
- In cordis.yml nur Provider- und Consumer-Zeilen aufführen; Anbieterwechsel durch Austausch einer Zeile.
Szenario D: Einen neuen Modellanbieter anbinden
- LlmAdapter erben und stream() implementieren, Ausgabe nach StreamChunk-Protokoll; Fehler mit stabilem code als LlmError (oder innerhalb des Streams als finish { kind: 'error' | 'aborted' }); attributionHeaders() pro HTTP-Request anhängen und signal weiterleiten.
- ctx.llm.registerAdapter([''], adapter); optional resolveModel()/listModels() überschreiben.
- Im kombinierten Setup die provider/model-Konfiguration des agent-loop validieren. Details in references/llm-adapter.md (enthält 7 Protokollpflichten).
Szenario E: Paketierung und Auslieferung
- Kombinationspaket erstellen: package.json deklariert dsh.bundle (zeigt auf cordis.patch.yml), Patch-Zeilen referenzieren das Plugin mit Paketnamen; reine Import-Bibliothekspakete deklarieren kein dsh.bundle.
- Installation: dsh plugin --profile add ; zuerst dsh --profile --dump-config zur Schichten-Validierung, dann starten.
- Schichtreihenfolge und Semantik des vollständigen Zeilenaustauschs beachten (references/packaging.md).
Szenario F: Neues Paket im DSH-Monorepo erstellen
Gemäß der dateiweisen Checkliste in references/workspace-package.md: Paket erstellen (package.json-Invarianten/tsconfig/src/README) → Root-Konfiguration registrieren → Paket-Topologie und -Benennung (Rollenwortliste) → README Model Experience-Struktur → Validierungsbefehle.
Entscheidungs-Spickzettel
| Ich möchte… | Mechanismus | Details |
|---|---|---|
| Fähigkeiten für andere Plugins bereitstellen | Service (Klassenform) | references/services.md |
| Vorhandene Fähigkeiten nutzen | inject oder ctx.get() | references/services.md |
| Kommunikation zwischen Plugins / Erweiterungspunkte | ctx.on / ctx.emit etc. (fünf Verteilungsmodi) | references/events.md |
| Dem Benutzer Konfiguration ermöglichen | Config + Schemastery | references/config.md |
| Dem Modell Fähigkeiten hinzufügen | defineTool → ctx.tools.register (oder rohes JSON Schema) | references/tools.md |
| Neuen Modellanbieter anbinden | LlmAdapter + ctx.llm.registerAdapter | references/llm-adapter.md |
| Austauschbare Fähigkeiten aufteilen | Drei Rollen (Definition/Provider/Consumer) | references/three-roles.md |
| Plugin verteilen | Kombinationspaket + Profile | references/packaging.md |
| Eingebaute Dienste / Zuordnungspositionen nachschlagen | seam-Verzeichnis, Architektur-Mapping | references/seams.md |
| Scopes / Dienstspeicherung / Fiber-API | ctx.extend/isolate/provide/mixin, fiber.* | references/context-api.md |
| Hooks / UI / Panels / Protokollbrücken-Plugins | Fünf Erweiterungsformen + Funktions-zu-Mechanismus-Mapping | references/plugin-forms.md |
| Browser-Seitiges Panel ruft Hauptprozess-Dienst auf | ctx.connection.rpc.handle/call, Endpunkt + Umschlag | references/connection-rpc.md |
| Neues Paket im Repository erstellen / benennen | Workspace-Paketliste + Rollenwortliste | references/workspace-package.md |
Checkliste vor Fertigstellung
- Schnittstellen an generierter Referenz geprüft (Dienste/Ereignisse/ctx-Keys richten sich nach Generierung), API nicht nur aus Namen geraten.
- Alle Registrierungen über ctx (Ereignisse/Werkzeuge/Adapter/effect), bei Deaktivierung bereinigt; bereinigungsreihenfolge-sensitive Logik im selben ctx.effect.
- Erforderliche Abhängigkeiten korrekt deklariert; optionale Abhängigkeiten mit undefined-Behandlung.
- Plugin mit Config: Config mit Schemastery, Standardwerte im Schema, ungültige Konfiguration führt beim Laden zu lautem Fehler.
- Werkzeug vorhanden: execute gibt normierte JSON-Werte zurück; render kümmert sich um menschliche Lesbarkeit; Strategie über tools/*-Events; exec.signal beachtet; Concurrency-Sicherheit mit isConcurrencySafe deklariert (undeklariert → exclusive).
- Waterfall-Listener vorhanden: next() aufgerufen und zurückgegeben (außer bei beabsichtigtem Kurzschluss).
- LLM-Adapter vorhanden: StreamChunk-Protokoll vollständig (Chunk-Paarung, index beim ersten Auftreten, usage vor finish, arguments durchgehend roher JSON-String); Fehler über einen der beiden erlaubten Pfade; nicht unterstützte Felder werfen UNSUPPORTED; bei nativer Wiederholung finish.replayState senden; attributionHeaders und signal übergeben.
- Kombinationszeilen und Schichtreihenfolge korrekt; neue Zeilen in --dump-config sichtbar; nach HMR/Neustart keine verbleibenden Registrierungen.
- Wenn sich modellsichtbarer Inhalt ändert: in einem Mechanismus, der das Log rekonstruieren kann.
- Browser-Seitiges Einstellungspanel: bevorzugt
ctx.connection.rpc.handle/call; kein nacktes@Remote, kein händisches Typert-Manifest, keincreateRequirezum Einhängen von Harness-Quellcode; vollständige Typert-Generator-Ausgabe +./typert+./remoteweiterhin gültig. - Neues Workspace-Paket: package.json-Invarianten, genau ein Aggregate, Benennung nach Rollenwortliste, README mit Model Experience-Struktur und constraints/typecheck/lint/build/hygiene komplett grün.
Referenzdateien (bei Bedarf laden, nicht auf einmal lesen)
Vollständiger Index und „Wann lesen“-Tabelle in references/README.md.
- references/plugin-anatomy.md – Beim Schreiben/Ändern eines Plugins, Behandeln des Lebenszyklus oder HMR
- references/services.md – Beim Definieren oder Nutzen eines Dienstes, Injizieren von Abhängigkeiten
- references/events.md – Bei Ereigniskommunikation, Lauschen auf Erweiterungspunkte
- references/config.md – Wenn das Plugin konfigurierbar sein soll
- references/context-api.md – Bei Verwendung von Scopes, Dienstspeicherung oder Fiber-API
- references/three-roles.md – Zum Aufteilen austauschbarer Fähigkeiten
- references/tools.md – Bei der Entwicklung von Modellwerkzeugen
- references/llm-adapter.md – Beim Anbinden eines neuen Modellanbieters
- references/plugin-forms.md – Beim Schreiben von Hook/UI/Protokollbrücken-Plugins
- references/connection-rpc.md – Wenn das npm-Einstellungspanel Hauptprozess-Methoden aufrufen muss; auch bei nacktem
@Remote/ händischem Manifest /createRequire-Quellcodebrücke - references/packaging.md – Beim Paketieren, Installieren und Ausliefern von Plugins
- references/workspace-package.md – Beim Erstellen eines neuen Pakets im Monorepo
- references/seams.md – Zum Nachschlagen eingebauter Dienste, Zuordnungspositionen oder Architektur-Mapping
Validierung
- Selbstprüfung: name in kebab-case und mit Verzeichnisname identisch; description nicht leer und prägnant (diese Skill unter 500 Zeichen); Text in Standard-Markdown; alle referenzierten references-Dateien existieren tatsächlich.
- Verzeichnisbenennung: Der Skill-Name (name) lautet dsh-plugin-dev, unterscheidet sich vom Hosting-Repository-Namen dsh-plugin-dev-skills – nach dem Klonen/Entpacken MUSS das Verzeichnis in dsh-plugin-dev umbenannt werden (entsprechend name), sonst könnte der über den Verzeichnisnamen adressierende Loader diese Skill nicht finden.
- In Umgebungen mit skills-ref CLI ausführbar: skills-ref validate ./dsh-plugin-dev
- Regression auslösen: Nach Änderung der description das Evaluierungsset evals/trigger-queries.json ausführen (Methode im Repository evals/README.md).
- Verhaltensvalidierung: Szenario A mit einem minimalen Plugin durchspielen (Ladelogs + Entladebereinigung), dann Szenario B mit einem greet-Werkzeug durchspielen.