# Plug-In-Verzeichnisse

Ein Plug-In ist ein Verzeichnis, das SDK-Erweiterungen – Fähigkeiten, Hooks, MCP-Server, benutzerdefinierte Agents und LSP-Konfiguration – hinter einem einzigen Manifest gebündelt. Wenn Sie auf das SDK in einem Plug-In-Verzeichnis verweisen, wird alles geladen, was das Plug-In beiträgt, sodass Sie wiederverwendbare Funktionspakete versenden können, ohne die Kabel pro Erweiterung in jeder Hostanwendung zu schreiben.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

In diesem Handbuch wird die Struktur des Plug-in-Ordners erläutert, wie Sie ein Plug-in aus einem Verzeichnis laden, wann Plug-in-Verzeichnisse im Vergleich zur Registrierung einzelner Erweiterungen verwendet werden sollten und wie Plug-in-Sets deterministisch gemacht werden.

## Wann Plugin-Verzeichnisse verwendet werden sollten

Verwenden Sie ein Plug-In-Verzeichnis, wenn Sie folgendes möchten:

* **Verteilen Sie ein Bündel von Fähigkeiten** als Einheit — z. B. ein „TypeScript Reviewer“-Paket mit einer Fähigkeit, einem `preToolUse` Hook, der die Linting-Regeln erzwingt, und einem benutzerdefinierten Agenten, der den Reviewer ausführt.
* **Anbieterfunktionspakete in ein Repository** , sodass jeder Klon der Hostanwendung die gleichen Erweiterungen deterministisch lädt.
* **Entwickeln Sie ein Plug-In lokal** , bevor Sie es auf einem Marketplace veröffentlichen.
* **Überschreiben oder Erweitern** eines marketplace-installierten Plug-Ins mit einem lokalen Auschecken zu Testzwecken.

Wenn Sie nur einen einzelnen MCP-Server, einen einzelnen Hook oder einen einzelnen benutzerdefinierten Agent hinzufügen müssen, können Sie ihn inline über die SDK-Konfiguration (`mcpServers`, , `hooks``customAgents`) registrieren. Plug-In-Verzeichnisse sind am nützlichsten, sobald Sie drei oder mehr verwandte Erweiterungen haben, die zusammen ausgeliefert werden.

## Plugin-Ordnerstruktur

Die Copilot CLI durchsucht jedes Plug-In-Verzeichnis nach einem `plugin.json`-Manifest oder einer `SKILL.md` im Stammverzeichnis. Ein minimales Plug-In sieht wie folgt aus:

```text
my-plugin/
├── plugin.json              # manifest (required unless using SKILL.md only)
├── SKILL.md                 # optional: top-level skill
├── hooks.json               # optional: hooks config
├── .mcp.json                # optional: MCP server config
├── agents/                  # optional: custom agents (one .md file per agent)
│   └── code-reviewer.md
└── skills/                  # optional: additional skills
    └── lint-fix/
        └── SKILL.md
```

Das Manifest kann sich auch unter `.github/plugin.json` oder `.github/plugin/plugin.json` befinden, sodass Plugins in einem vorhandenen Repository liegen können, ohne dessen Stammverzeichnisstruktur zu ändern. Jedes Subsystem (Hooks, MCP, LSP, Skills, Agents) verfügt über einen eigenen Loader und ist optional – ein Plugin benötigt nur die Teile, die es beisteuert.

Das vollständige Manifestschema finden Sie in der Laufzeitdokumentation, auf die im Schrägstrichbefehl `/plugin` Ihrer CLI verwiesen wird.

## Laden eines Plug-In-Verzeichnisses aus dem SDK

Plug-In-Verzeichnisse werden geladen, indem `--plugin-dir <path>` an die Copilot CLI übergeben werden, wenn das SDK sie spawns. Jede Sprache macht dies über die Extra-Args-Option der Laufzeitverbindung verfügbar. Das Flag kann wiederholt werden, um mehrere Plug-ins zu laden.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";

const client = new CopilotClient({
  connection: RuntimeConnection.forStdio({
    args: [
      "--plugin-dir", "./plugins/code-reviewer",
      "--plugin-dir", "./plugins/lint-fix",
    ],
  }),
});

await client.start();
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: wrap-async -->

```python
from copilot import CopilotClient, StdioRuntimeConnection

client = CopilotClient(
    connection=StdioRuntimeConnection(
        args=(
            "--plugin-dir", "./plugins/code-reviewer",
            "--plugin-dir", "./plugins/lint-fix",
        ),
    ),
)
await client.start()
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
client := copilot.NewClient(&copilot.ClientOptions{
    Connection: copilot.StdioConnection{
        Args: []string{
            "--plugin-dir", "./plugins/code-reviewer",
            "--plugin-dir", "./plugins/lint-fix",
        },
    },
})
if err := client.Start(ctx); err != nil {
    return err
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient(new CopilotClientOptions
{
    Connection = RuntimeConnection.ForStdio(args: new[]
    {
        "--plugin-dir", "./plugins/code-reviewer",
        "--plugin-dir", "./plugins/lint-fix",
    }),
});

await client.StartAsync();
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
var options = new CopilotClientOptions()
    .setCliArgs(new String[] {
        "--plugin-dir", "./plugins/code-reviewer",
        "--plugin-dir", "./plugins/lint-fix",
    });

var client = new CopilotClient(options);
client.start().get();
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

```rust
use github_copilot_sdk::{Client, ClientOptions};

let client = Client::start(
    ClientOptions::new().with_extra_args([
        "--plugin-dir", "./plugins/code-reviewer",
        "--plugin-dir", "./plugins/lint-fix",
    ]),
)
.await?;
```

</div>

</div>

> Im obigen Beispiel wird eine Stdio-Laufzeitverbindung verwendet– der Standardwert, wenn das SDK die CLI bündelt. Wenn Sie über eine URL (`forUri` / `ForUri`) eine Verbindung zu einer externen Laufzeit herstellen, übergeben Sie `--plugin-dir` beim Starten an den langlebigen CLI-Server; das SDK leitet `--plugin-dir` nicht an Laufzeiten weiter, die es nicht selbst gestartet hat.

## Vertrauenswürdige Host-gebündelte Plug-In-Verzeichnisse

Anwendungen, die ihre eigenen vertrauenswürdigen Plug-Ins versenden, können sie als Clientstartoption registrieren. Das SDK sendet die vollständige geordnete Menge nach dem Herstellen der Verbindung und der Überprüfung des Protokolls, bevor `start` zurückkehrt oder eine Sitzung erstellt werden kann. Pfade müssen absolut sein; wenn die Option nicht gesetzt oder leer ist, erfolgt kein RPC-Aufruf.

Die entsprechende Option in jedem SDK lautet:

| SDK                  | Startoption                                           |
| -------------------- | ----------------------------------------------------- |
| Node.js / TypeScript | `builtinPluginDirectories: string[]`                  |
| Python               | `builtin_plugin_directories=[...]`                    |
| Go                   | `BuiltinPluginDirectories: []string{...}`             |
| .NET                 | `BuiltinPluginDirectories = [...]`                    |
| Java                 | `.setBuiltinPluginDirectories(List.of(Path.of(...)))` |
| Rust                 | `.with_builtin_plugin_directories([...])`             |

Dies ist eine Vertrauensgrenze für Plugins, die gebündelt und von der Hostanwendung gesteuert werden. Es unterscheidet sich von `--plugin-dir`einem CLI-Prozessstartargument zum expliziten Laden gewöhnlicher Plug-In-Verzeichnisse. Die Startoption funktioniert auch beim Herstellen einer Verbindung mit einer vorhandenen Laufzeit, da sie über JSON-RPC und nicht als Prozessargument weitergeleitet wird.

## Was ein Plug-In beitragen kann

Das Laden eines Plug-In-Verzeichnisses macht seine Erweiterungen für jede vom Client erstellte Sitzung sichtbar. Die Laufzeit führt von Plug-ins bereitgestellte Erweiterungen mit allem zusammen, was Sie inline registrieren:

| Plugin leistet einen Beitrag                  | Für Sitzung sichtbar als                                             |
| --------------------------------------------- | -------------------------------------------------------------------- |
| Fähigkeiten (`SKILL.md`, `skills/*/SKILL.md`) | Elemente in `session.skills.list()`; injizierbar nach Name           |
| Benutzerdefinierte Agenten (`agents/*.md`)    | Verteilbar über das `task(agent_type=...)` Tool                      |
| Hooks (`hooks.json`)                          | Wird zusammen mit Hooks ausgelöst, die über das SDK registriert sind |
| MCP-Server (`.mcp.json`)                      | Werkzeuge und Ressourcen, die über `session.mcp.*` erreichbar sind   |
| LSP-Server (`.lsp.json`)                      | Initialisiert über `session.lsp.initialize(...)`                     |

Plug-in-Agents sind erstklassige Sub-Agents in [Flottenmodus](/de/copilot/how-tos/copilot-sdk/features/fleet-mode): Ein übergeordneter Agent kann sie über `agent_type` aufrufen, und die Laufzeit löst die Hooks `subagentStart` / `subagentStop` für sie wie bei jedem anderen Sub-Agenten aus.

## Plugin-Verzeichnis vs. Marketplace-Plugins

Die Laufzeitumgebung bietet zwei Möglichkeiten, Plugins zu installieren, und beide sehen für eine Sitzung gleich aus:

* **Marketplace-/Direct-Repo-Plugins** werden dauerhaft über den Slash-Befehl der CLI `/plugin` oder die zugrunde liegende Nutzereinstellung `installedPlugins` installiert. Sie sind *global verfügbar* – jede Sitzung, die mit derselben Benutzerkonfiguration ausgeführt wird, hat Zugriff darauf, und sie werden bei den Regeln zur Plug-in-Erkennung berücksichtigt.
* **`--plugin-dir` Plugins** sind *explizit und kurzlebig* – sie gelten nur für den CLI-Prozess, den Sie mit dieser Kennzeichnung gestartet haben. Sie haben Vorrang vor ambient discovery und werden gegen Marketplace-Einträge mit demselben Cachepfad dedupliziert, sodass dasselbe Plug-In nicht zweimal geladen wird, wenn beide Oberflächen darauf verweisen.

Für SDK-basierte Anwendungen ist `--plugin-dir` in der Regel die richtige Wahl: Es hält den Plug-In-Satz unter der Kontrolle Ihrer Anwendung, anstatt vom benutzerspezifischen Zustand des jeweiligen Rechners abzuhängen.

## Deterministisches Erstellen von Plug-in-Sets

Wenn auf der Hostmaschine möglicherweise andere Plugins installiert sind (aus dem Marketplace oder eigene), setzen Sie `COPILOT_PLUGIN_DIR_ONLY=true` in den Umgebungsvariablen der Laufzeitumgebung, um die automatische Erkennung von Plugins zu unterdrücken. Nur die Verzeichnisse, die Sie über `--plugin-dir` übergeben, werden geladen.

<details open>
<summary>
<strong>Node.js / TypeScript</strong></summary>

```typescript
process.env.COPILOT_PLUGIN_DIR_ONLY = "true";

const client = new CopilotClient({
  connection: RuntimeConnection.forStdio({
    args: ["--plugin-dir", "./plugins/code-reviewer"],
  }),
});
await client.start();
```

</details>

Verwenden Sie dies in CI, in Headless-Serverbereitstellungen und überall, wo Sie einen reproduzierbaren Plug-In-Satz wünschen, der nicht von der Benutzerkonfiguration des Hosts abhängt.

## Prüfen, welche Plug-Ins geladen wurden

Sobald eine Sitzung erstellt wurde, führen Sie die aktiven Plug-Ins auf, um zu bestätigen, dass ein Verzeichnis richtig aufgenommen wurde:

<details open>
<summary>
<strong>Node.js / TypeScript</strong></summary>

```typescript
const plugins = await session.rpc.plugins.list();
for (const plugin of plugins.plugins) {
  console.log(`${plugin.name} (${plugin.enabled ? "enabled" : "disabled"})`);
}
```

</details>

Plugins, die über `--plugin-dir` geladen werden, erscheinen in dieser Liste, wobei ihr Cachepfad auf das von Ihnen angegebene Verzeichnis gesetzt ist. Marketplace-Installationen werden mit ihrer Registrierungsquelle markiert.

## Troubleshooting

* **"keine plugin.json oder SKILL.md in \<dir> gefunden"** – das Verzeichnis ist vorhanden, gilt aber nicht als Plugin. Fügen Sie ein `plugin.json` Manifest im Stammverzeichnis (oder unter `.github/`) hinzu, oder fügen Sie eine oberste Ebene `SKILL.md`ein.
* **Plug-In geladen, aber Agents/Fähigkeiten nicht sichtbar** - stellen Sie sicher, dass das Plug-In-Manifest die Agents/Fähigkeiten deklariert, die es beiträgt, oder verwenden Sie das implizite Layout (`agents/*.md`, `skills/*/SKILL.md`). Rufen Sie dann auf `session.rpc.skills.reload()` , um Änderungen ohne Neustart zu übernehmen.
* **Doppelte Hooks werden ausgeführt** – die Laufzeit dedupliziert anhand von `cache_path`, aber nur, wenn auf dasselbe Verzeichnis sowohl als Marketplace-Installation als auch als `--plugin-dir` verwiesen wird. Wenn zwei verschiedene Verzeichnisse dasselbe Plug-In enthalten, werden beide geladen. Entfernen Sie eine oder verwenden Sie `COPILOT_PLUGIN_DIR_ONLY=true`.
* **`--plugin-dir` wird bei der Verbindung mit einer externen Laufzeit ignoriert** – das SDK leitet zusätzliche Argumente nur weiter, wenn es die CLI selbst startet. Für externe Laufzeiten (`forUri`/`ForUri`) übergeben Sie `--plugin-dir` in der Befehlszeile, mit der der Laufzeitserver gestartet wird.

## Verwandte Themen

* [Angepasste Agents und Orchestrierung von Unteragenten](/de/copilot/how-tos/copilot-sdk/features/custom-agents): Agenten schreiben, die im `agents/`Ordner des Plug-ins enthalten sind.
* [Benutzerdefinierte Fähigkeiten](/de/copilot/how-tos/copilot-sdk/features/skills): Wie `SKILL.md` Dateien geladen werden, und die Regeln für die Reihenfolge der Fähigkeiten.
* [Arbeiten mit Hooks](/de/copilot/how-tos/copilot-sdk/features/hooks): Von einem Plugin definierte Hooks werden zusammen mit den vom SDK registrierten Hooks ausgelöst.
* [Verwenden von MCP-Servern mit dem GitHub Copilot SDK](/de/copilot/how-tos/copilot-sdk/features/mcp): Von Plugins bereitgestellte MCP-Server werden auf die gleiche Weise wie Inline-Registrierungen integriert.
* [Flottenmodus](/de/copilot/how-tos/copilot-sdk/features/fleet-mode): Von Plugins bereitgestellte Agenten können als Sub-Agenten eingesetzt werden.