{"meta":{"title":"Каталоги плагинов","intro":"Плагин — это каталог, который объединяет расширения SDK — навыки, хуки, MCP-серверы, пользовательские агенты и конфигурацию LSP — за одним манифеста. Указание SDK на каталог плагинов загружает всё, что добавляет плагин, так что вы можете отправлять повторно используемые пакеты возможностей без записи проводки по разным расширениям в каждом хост-приложении.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/copilot","title":"GitHub Copilot"},{"href":"/ru/copilot/how-tos","title":"Инструкции"},{"href":"/ru/copilot/how-tos/copilot-sdk","title":"Второй пилот SDK"},{"href":"/ru/copilot/how-tos/copilot-sdk/features","title":"Возможности"},{"href":"/ru/copilot/how-tos/copilot-sdk/features/plugin-directories","title":"Каталоги плагинов"}],"documentType":"article"},"body":"# Каталоги плагинов\n\nПлагин — это каталог, который объединяет расширения SDK — навыки, хуки, MCP-серверы, пользовательские агенты и конфигурацию LSP — за одним манифеста. Указание SDK на каталог плагинов загружает всё, что добавляет плагин, так что вы можете отправлять повторно используемые пакеты возможностей без записи проводки по разным расширениям в каждом хост-приложении.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\nВ этом руководстве объясняется структура папок плагинов, как загружать плагин из каталога, когда использовать каталоги плагинов и когда регистрировать отдельные расширения, а также как сделать наборы плагинов детерминированными.\n\n## Когда использовать каталоги плагинов\n\nИспользуйте папку плагинов, когда хотите:\n\n* **Распределите набор возможностей** в одном едином блоке — например, пакет «TypeScript reviewer» с навыком, `preToolUse` крючок, обеспечивающий линт, и пользовательский агент, управляющий рецензентом.\n* **Возможности поставщика упаковываются в репозиторий** , так что каждый клон хост-приложения загружает одни и те же расширения детерминированно.\n* **Разработайте плагин локально** перед тем, как публиковать его на маркетплейсе.\n* **Переопределите или расширите** плагин, установленный на маркетплейсе, с помощью локальной проверки для тестирования.\n\nЕсли вам нужно добавить только один MCP-сервер, один крюк или один пользовательский агент, вы можете зарегистрировать его в строке через конфигурацию SDK (`mcpServers`, `hooks`, `customAgents`). Папки плагинов наиболее полезны, когда у вас есть три или более связанных расширений, которые поставляются вместе.\n\n## Оформление папки плагина\n\nCopilot CLI сканирует каждую папку плагина в поисках манифеста `plugin.json` или корневого уровня `SKILL.md`. Минимальный плагин выглядит так:\n\n```text\nmy-plugin/\n├── plugin.json              # manifest (required unless using SKILL.md only)\n├── SKILL.md                 # optional: top-level skill\n├── hooks.json               # optional: hooks config\n├── .mcp.json                # optional: MCP server config\n├── agents/                  # optional: custom agents (one .md file per agent)\n│   └── code-reviewer.md\n└── skills/                  # optional: additional skills\n    └── lint-fix/\n        └── SKILL.md\n```\n\nМанифест также может находиться в точке `.github/plugin.json` или `.github/plugin/plugin.json` около того, что плагины могут находиться внутри существующего репозитория без изменения его корневой структуры. Каждая подсистема (хуки, MCP, LSP, навыки, агенты) имеет свой загрузчик и является опциональной — плагину нужны только те части, которые он вносит.\n\nПолную схему манифеста смотрите документацию по выполнению, на которую ссылка из команды слэш вашего `/plugin` CLI.\n\n## Загрузка каталога плагинов из SDK\n\nКаталоги плагинов загружаются путём передачи `--plugin-dir <path>` Copilot CLI, когда SDK его создаёт. Каждый язык раскрывает это через опцию extra args в runtime connection. Флаг можно повторить для загрузки нескольких плагинов.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient, RuntimeConnection } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient({\n  connection: RuntimeConnection.forStdio({\n    args: [\n      \"--plugin-dir\", \"./plugins/code-reviewer\",\n      \"--plugin-dir\", \"./plugins/lint-fix\",\n    ],\n  }),\n});\n\nawait client.start();\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n<!-- docs-validate: wrap-async -->\n\n```python\nfrom copilot import CopilotClient, StdioRuntimeConnection\n\nclient = CopilotClient(\n    connection=StdioRuntimeConnection(\n        args=(\n            \"--plugin-dir\", \"./plugins/code-reviewer\",\n            \"--plugin-dir\", \"./plugins/lint-fix\",\n        ),\n    ),\n)\nawait client.start()\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nclient := copilot.NewClient(&copilot.ClientOptions{\n    Connection: copilot.StdioConnection{\n        Args: []string{\n            \"--plugin-dir\", \"./plugins/code-reviewer\",\n            \"--plugin-dir\", \"./plugins/lint-fix\",\n        },\n    },\n})\nif err := client.Start(ctx); err != nil {\n    return err\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing GitHub.Copilot;\n\nawait using var client = new CopilotClient(new CopilotClientOptions\n{\n    Connection = RuntimeConnection.ForStdio(args: new[]\n    {\n        \"--plugin-dir\", \"./plugins/code-reviewer\",\n        \"--plugin-dir\", \"./plugins/lint-fix\",\n    }),\n});\n\nawait client.StartAsync();\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\nvar options = new CopilotClientOptions()\n    .setCliArgs(new String[] {\n        \"--plugin-dir\", \"./plugins/code-reviewer\",\n        \"--plugin-dir\", \"./plugins/lint-fix\",\n    });\n\nvar client = new CopilotClient(options);\nclient.start().get();\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nuse github_copilot_sdk::{Client, ClientOptions};\n\nlet client = Client::start(\n    ClientOptions::new().with_extra_args([\n        \"--plugin-dir\", \"./plugins/code-reviewer\",\n        \"--plugin-dir\", \"./plugins/lint-fix\",\n    ]),\n)\n.await?;\n```\n\n</div>\n\n</div>\n\n> Приведённый выше пример использует stdio runtime соединение — стандартное, когда SDK объединяет CLI. Если вы подключаетесь к внешнему серверу выполнения через URL (`forUri` / `ForUri`), передайте данные `--plugin-dir` на долгоработающий CLI-сервер при запуске; SDK не пересылает `--plugin-dir` время выполнения, которые он не создал.\n\n## Каталоги подключаемых модулей с доверенными узлами\n\nПриложения, отправившие собственные доверенные подключаемые модули, могут зарегистрировать их в качестве варианта запуска клиента. Пакет SDK отправляет полный упорядоченный набор после подключения и проверки протокола перед `start` возвратом или любым сеансом. Пути должны быть абсолютными; Если параметр не задан или пуст, вызов RPC не вызывается.\n\nЭквивалентный вариант в каждом пакете SDK:\n\n| SDK                  | Параметр запуска                                      |\n| -------------------- | ----------------------------------------------------- |\n| Node.js / TypeScript | `builtinPluginDirectories: string[]`                  |\n| Python               | `builtin_plugin_directories=[...]`                    |\n| Go                   | `BuiltinPluginDirectories: []string{...}`             |\n| .NET                 | `BuiltinPluginDirectories = [...]`                    |\n| Java                 | `.setBuiltinPluginDirectories(List.of(Path.of(...)))` |\n| Rust                 | `.with_builtin_plugin_directories([...])`             |\n\nЭто граница доверия для подключаемых модулей, упакованных и контролируемых ведущим приложением. Это отличается от `--plugin-dir`аргумента запуска CLI для явной загрузки обычных каталогов подключаемых модулей. Параметр запуска также работает при подключении к существующей среде выполнения, так как он отправляется через JSON-RPC, а не пересылается в качестве аргумента процесса.\n\n## Что может внести плагин\n\nЗагрузка каталога плагинов делает его расширения видимыми для каждой сессии, созданной клиентом. Runtime объединяет расширения, предоставленные плагинами, с тем, что вы регистрируете в строке:\n\n| Плагин вносит вклад                      | Видимо для сессии как                                          |\n| ---------------------------------------- | -------------------------------------------------------------- |\n| Навыки (`SKILL.md`, `skills/*/SKILL.md`) | Элементы в `session.skills.list()`; инъекциируемые по названию |\n| Таможенные агенты (`agents/*.md`)        | Можно отправить с помощью `task(agent_type=...)` инструмента   |\n| Крючки (`hooks.json`)                    | Стреляет вместе с крюками, зарегистрированными через SDK       |\n| MCP-серверы (`.mcp.json`)                | Инструменты и ресурсы, доступные через `session.mcp.*`         |\n| LSP-серверы (`.lsp.json`)                | Инициализация с помощью `session.lsp.initialize(...)`          |\n\nАгенты плагинов — это первоклассные субагенты в [Режим флота](/ru/copilot/how-tos/copilot-sdk/features/fleet-mode): родительский агент может отправить их через `agent_type`, и runtime запускает `subagentStart` / `subagentStop` крючки для них, как и любой другой подагент.\n\n## Plugin-dir против плагинов marketplace\n\nВ среде выполнения есть два способа установки плагинов, и оба в итоге выглядят одинаково для сессии:\n\n* **Плагины Marketplace / прямой репозиторий** постоянно устанавливаются через команду слэш CLI `/plugin` или через базовую `installedPlugins` пользовательскую настановку. Они *окружающие* — каждая сессия, работающая с одной и той же пользовательской конфигурацией, видит их, и они участвуют в правилах обнаружения плагинов.\n* **`--plugin-dir` плагины***явны и эфемерны* — они применимы только к CLI-процессу, который вы запустили с этим флагом. Они имеют приоритет над окружающим обнаружением и удаляются по сравнению с записями на рынке с одинаковым кэш-маршрутом, поэтому один и тот же плагин не загружается дважды, когда обе поверхности на него ссылаются.\n\nДля приложений, управляемых SDK, `--plugin-dir` обычно это правильный выбор: плагин остаётся под контролем вашего приложения, а не зависит от состояния пользователя на каждой машине.\n\n## Детерминированные наборы плагинов\n\nКогда на хост-машине могут быть установлены другие плагины (маркетплейсовые или личные), они устанавливаются `COPILOT_PLUGIN_DIR_ONLY=true` в среде выполнения для подавления автоматического обнаружения плагинов. Загружаются только те каталоги, через `--plugin-dir` которые вы проходите.\n\n<details open>\n<summary>\n<strong>Node.js / TypeScript</strong></summary>\n\n```typescript\nprocess.env.COPILOT_PLUGIN_DIR_ONLY = \"true\";\n\nconst client = new CopilotClient({\n  connection: RuntimeConnection.forStdio({\n    args: [\"--plugin-dir\", \"./plugins/code-reviewer\"],\n  }),\n});\nawait client.start();\n```\n\n</details>\n\nИспользуйте это в CI, в развертённых серверах без головы и везде, где нужен воспроизводимый набор плагинов, не зависящий от конфигурации пользователя хоста.\n\n## Проверка загрузки плагинов\n\nПосле создания сессии перечислите активные плагины, чтобы убедиться, что каталог был правильно выбран:\n\n<details open>\n<summary>\n<strong>Node.js / TypeScript</strong></summary>\n\n```typescript\nconst plugins = await session.rpc.plugins.list();\nfor (const plugin of plugins.plugins) {\n  console.log(`${plugin.name} (${plugin.enabled ? \"enabled\" : \"disabled\"})`);\n}\n```\n\n</details>\n\nПлагины, загруженные через `--plugin-dir` BY, появляются в этом списке с их кэш-путём, установленным в указанной вами директории. Установки маркетплейса отмечены исходным кодом реестра.\n\n## Troubleshooting\n\n* **\"нет plugin.json или SKILL.md в \\<DIR>\"** — каталог существует, но не считается плагином. Добавьте `plugin.json` манифест в корень (или ниже `.github/`), или добавьте верхний уровень `SKILL.md`.\n* **Плагин загружен, но агенты/навыки не видны** — убедитесь, что манифест плагина объявляет агентов/навыков, которые он вносит, или используйте неявную структуру (`agents/*.md`, `skills/*/SKILL.md`). Потом звоните `session.rpc.skills.reload()` , чтобы забрать изменения, не перезагружаясь.\n* **Срабатывание дублирующих крючков** — время выполнения дедуплирует на `cache_path`, но только тогда, когда одна и та же папка ссылается как на установку маркетплейса, так и на `--plugin-dir`. Если два разных каталога содержат один и тот же плагин, оба будут загружаться. Удалите один или используйте `COPILOT_PLUGIN_DIR_ONLY=true`.\n* **`--plugin-dir` игнорируется при подключении к внешнему runtime** — SDK пересылает дополнительные arg-файлы только при создании самого CLI. Для внешних условий выполнения (`forUri`/`ForUri`), передайте `--plugin-dir` командную строку, которая запускает сервер выполнения.\n\n## Related\n\n* [Пользовательские агенты и оркестровка субагентов](/ru/copilot/how-tos/copilot-sdk/features/custom-agents): пишите агенты, которые отправляются внутри папки `agents/` плагина.\n* [Настраиваемые навыки](/ru/copilot/how-tos/copilot-sdk/features/skills): как `SKILL.md` загружаются файлы и правила порядка уровней навыков.\n* [Работа с крючками](/ru/copilot/how-tos/copilot-sdk/features/hooks): хуки, определяемые плагинами, вместе с хуками, зарегистрированными в SDK.\n* [Использование MCP-серверов с SDK GitHub Copilot](/ru/copilot/how-tos/copilot-sdk/features/mcp): MCP-серверы, предоставляемые плагинами, интегрируются так же, как и встроенные регистрации.\n* [Режим флота](/ru/copilot/how-tos/copilot-sdk/features/fleet-mode): агенты, предоставленные плагинами, могут диспетчеризироваться как субагенты."}