Este guia explica o layout da pasta do plug-in, como carregar um plug-in de um diretório, quando usar diretórios de plug-in versus registrar extensões individuais e como tornar os conjuntos de plug-in determinísticos.
Quando usar diretórios de plug-in
Use um diretório de plug-in quando quiser:
- Distribua um pacote de capacidades como uma única unidade — por exemplo, um pacote "revisor TypeScript" com uma habilidade, um
preToolUsehook que aplica a verificação de lint e um agente personalizado que executa o revisor. - A funcionalidade do fornecedor é empacotada em um repositório para que cada clone do aplicativo host carregue as mesmas extensões deterministicamente.
- Desenvolva um plug-in localmente antes de publicá-lo em um marketplace.
- Substitua ou estenda um plug-in instalado no marketplace com um check-out local para teste.
Se você precisar adicionar apenas um servidor MCP, um único gancho ou um único agente personalizado, você poderá registrá-lo embutido por meio da configuração do SDK (mcpServers, hooks, customAgents). Os diretórios de plug-in são mais úteis quando você tem três ou mais extensões relacionadas que são enviadas juntas.
Estrutura da pasta do plugin
A CLI do Copilot verifica cada diretório de plug-in para um manifesto plugin.json ou um SKILL.md de nível raiz. Um plug-in mínimo tem esta aparência:
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
O manifesto também pode ficar em .github/plugin.json ou .github/plugin/plugin.json, para que os plug-ins possam ficar dentro de um repositório existente sem alterar sua estrutura raiz. Cada subsistema (ganchos, MCP, LSP, habilidades, agentes) tem seu próprio carregador e é opcional – um plug-in só precisa das partes que ele contribui.
Para obter o esquema de manifesto completo, consulte a documentação de runtime referenciada no comando de barra da /plugin CLI.
Carregando um diretório de plug-in do SDK
Os diretórios de plug-in são carregados passando --plugin-dir <path> para a CLI do Copilot quando o SDK o gera. Cada idioma expõe isso por meio da opção extra-args da conexão de runtime. A flag pode ser repetida para carregar vários plugins.
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();
from copilot import CopilotClient, StdioRuntimeConnection
client = CopilotClient(
connection=StdioRuntimeConnection(
args=(
"--plugin-dir", "./plugins/code-reviewer",
"--plugin-dir", "./plugins/lint-fix",
),
),
)
await client.start()
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
}
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();
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();
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?;
O exemplo acima usa uma conexão de runtime stdio – o padrão quando o SDK agrupa a CLI. Se você se conectar a um runtime externo via uma URL (
forUri/ForUri), passe--plugin-dirpara o servidor CLI de longa duração ao iniciá-lo; o SDK não encaminha--plugin-dirpara runtimes que ele não iniciou.
Diretórios de plugin por sessão
--plugin-dir é um argumento de inicialização, portanto fixa um conjunto de plugins para o processo da CLI e para cada sessão criada com base nele. Quando as sessões precisarem de conjuntos de plug-ins diferentes, ou quando o SDK estiver conectado a um runtime que ele não iniciou, passe os diretórios na configuração da sessão. Eles trafegam nas session.resumecargas úteissession.create por JSON-RPC, em vez de como argumentos de processo, de modo que cheguem a um runtime externo da mesma forma que a opção de inicialização.
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
pluginDirectories: ["./plugins/code-reviewer"],
});
Caminhos relativos são resolvidos com base em workingDirectory, ou no diretório de trabalho do runtime quando ele não estiver definido, por isso caminhos absolutos são recomendados. As entradas que não podem ser resolvidas são registradas em log e puladas, em vez de fazer com que a criação da sessão falhe. A opção é uma aceitação explícita, o que significa que agentes de plug-in e regras são carregados mesmo quando enableConfigDiscovery é falso. Os ativos carregados dessa forma ficam entre fontes de projeto e fontes pessoais ou domésticas na ordem de precedência de toda a sessão.
A opção equivalente em cada SDK é:
| SDK | Opção de sessão |
|---|---|
| Node.js/TypeScript | plugin |
| Python | plugin_directories=[...] |
| Go | Plugin |
| .NET | PluginDirectories = [...] |
| Java | .set |
| Rust | .with_plugin_directories([...]) |
Diretórios de plug-in em pacote de host confiáveis
Os aplicativos que enviam seus próprios plug-ins confiáveis podem registrá-los como uma opção de inicialização do cliente. O SDK envia o conjunto ordenado completo após se conectar e verificar o protocolo, antes que start retorne ou que qualquer sessão possa ser criada. Os caminhos devem ser absolutos; deixar a opção não definida ou vazia não realiza nenhuma chamada RPC.
A opção equivalente em cada SDK é:
| SDK | Opção de inicialização |
|---|---|
| Node.js/TypeScript | builtin |
| Python | builtin_plugin_ |
| Go | Builtin |
| .NET | Builtin |
| Java | .set |
| Rust | .with_builtin_ |
Esse é um limite de confiança para plug-ins agrupados e controlados pelo aplicativo host. É diferente de --plugin-dir, que é um argumento de inicialização de processo da CLI para carregar explicitamente diretórios comuns de plug-ins. A opção de inicialização também funciona ao se conectar a um runtime existente porque é enviada por JSON-RPC em vez de encaminhada como um argumento de processo.
O que um plug-in pode contribuir
Carregar um diretório de plug-in torna suas extensões visíveis para cada sessão criada pelo cliente. O tempo de execução mescla as extensões fornecidas pelo plug-in com tudo o que você registra diretamente no código:
| O plugin contribui | Visível para a sessão como |
|---|---|
Habilidades (SKILL.md, skills/*/SKILL.md) | Itens no session.skills.list(); passíveis de injeção por nome |
Agentes personalizados (agents/*.md) | Pode ser enviado pela ferramenta task(agent_type=...) |
Ganchos (hooks.json) | Acionado junto com ganchos registrados por meio do SDK |
Servidores MCP (.mcp.json) | Ferramentas e recursos acessíveis por meio de session.mcp.* |
Servidores LSP (.lsp.json) | Inicializado por meio de session.lsp.initialize(...) |
Os agentes de plugin são subagentes de primeira classe em Modo de frota: um agente pai pode despachá-los por agent_type, e o ambiente de execução dispara os hooks subagentStart / subagentStop para eles como faz com qualquer outro subagente.
Plug-ins do diretório vs plug-ins do marketplace
O ambiente de execução tem duas maneiras de instalar plug-ins, e ambas acabam parecendo iguais para uma sessão:
- Os plugins do Marketplace / de repositório direto são instalados de forma persistente por meio do comando de barra da
/pluginCLI ou dainstalledPluginsconfiguração de usuário subjacente. Eles são globais — toda sessão executada com a mesma configuração de usuário consegue vê-los, e eles participam das regras de descoberta de plug-ins. --plugin-diros plug-ins são explícitos e efêmeros – eles se aplicam apenas ao processo da CLI que você iniciou com esse sinalizador. Eles têm precedência sobre a descoberta no ambiente e são desduplicados em relação às entradas do marketplace com o mesmo caminho de cache, de modo que o mesmo plug-in não seja carregado duas vezes quando ambas as origens fizerem referência a ele.
Para aplicativos baseados em SDK, --plugin-dir geralmente é a escolha certa: mantém o conjunto de plug-ins sob o controle da sua aplicação, em vez de depender do estado do usuário em cada máquina.
Tornando os conjuntos de plug-in determinísticos
Quando a máquina host puder ter outros plug-ins instalados (do marketplace ou personalizados), defina COPILOT_PLUGIN_DIR_ONLY=true no ambiente de execução para suprimir a descoberta automática de plug-ins. Somente os diretórios que você informar por meio de --plugin-dir serão carregados.
Node.js/TypeScript
process.env.COPILOT_PLUGIN_DIR_ONLY = "true";
const client = new CopilotClient({
connection: RuntimeConnection.forStdio({
args: ["--plugin-dir", "./plugins/code-reviewer"],
}),
});
await client.start();
Use isso em CI, em implantações de servidor sem cabeça e em qualquer lugar que você queira um conjunto de plug-in reproduzível que não dependa da configuração do usuário do host.
Inspecionando quais plug-ins foram carregados
Depois que uma sessão for criada, liste os plug-ins ativos para confirmar se um diretório foi selecionado corretamente:
Node.js/TypeScript
const plugins = await session.rpc.plugins.list();
for (const plugin of plugins.plugins) {
console.log(`${plugin.name} (${plugin.enabled ? "enabled" : "disabled"})`);
}
Plugins carregados via --plugin-dir aparecem nesta lista com o caminho do cache definido como o diretório que você forneceu. As instalações do Marketplace são marcadas com seu registro de origem.
Troubleshooting
- "nenhum plugin.json ou SKILL.md encontrado no <dir>" – o diretório existe, mas não se qualifica como um plug-in. Adicione um
plugin.jsonmanifesto na raiz (ou abaixo.github/) ou inclua um nívelSKILL.mdsuperior. - Plugin carregado, mas agentes/habilidades não estão visíveis — verifique se o manifesto do plugin declara os agentes/habilidades que ele fornece ou use o layout implícito (
agents/*.md,skills/*/SKILL.md). Em seguida, chamesession.rpc.skills.reload()para pegar as alterações sem reiniciar. - Hooks executados em duplicidade — o runtime elimina duplicatas por
cache_path, mas somente quando o mesmo diretório é referenciado tanto como uma instalação via marketplace quanto como um--plugin-dir. Se dois diretórios diferentes contiverem o mesmo plug-in, ambos serão carregados. Remova um ou useCOPILOT_PLUGIN_DIR_ONLY=true. --plugin-dirignorado ao se conectar a um runtime externo – o SDK só encaminha args extras quando gera a própria CLI. Para runtimes externos (forUri/ForUri), passe--plugin-dirna linha de comando que inicia o servidor de runtime.
Related
- Agentes personalizados e orquestração de subagentes: escreva agentes que são distribuídos na pasta de um plug-in
agents/. - Habilidades personalizadas: como
SKILL.mdarquivos são carregados e as regras de ordenação por nível de habilidade. - Trabalhando com ganchos: hooks definidos por um plugin são acionados junto com hooks registrados no SDK.
- Usando servidores MCP com o SDK do GitHub Copilot: os servidores MCP fornecidos pelo plug-in integram-se da mesma maneira que os registros embutidos.
- Modo de frota: agentes fornecidos por plug-in podem ser despachados como subagentes.