完全指南:打包 Skills、Hooks、MCP 与自定义 Agent 的单一加载单元)
GitHub Copilot SDK 插件目录Plugin Directories完全指南打包 Skills、Hooks、MCP 与自定义 Agent 的单一加载单元【免费下载链接】copilot-sdkMulti-platform SDK for integrating GitHub Copilot Agent into apps and services项目地址: https://gitcode.com/GitHub_Trending/co/copilot-sdk插件目录Plugin Directories是 GitHub Copilot SDK 提供的一种扩展打包机制一个plugin本质上是一个目录通过单一清单把 SDK 扩展skills、hooks、MCP servers、自定义 agents 以及 LSP 配置捆绑在一起。只需把这个目录指给 SDK插件贡献的所有扩展就会被一次性加载从而让你能在宿主应用中打包并分发可复用的能力包而无需在每一个宿主应用里编写逐项扩展的接线代码。本文以 docs/features/plugin-directories.md 为主线覆盖插件的目录布局、从 SDK 加载插件的三种途径CLI 启动参数、会话级配置、受信任的内置目录、插件与 marketplace 插件的区别、如何让插件集合具备确定性并结合仓库源码如 nodejs/src/client.ts、go/client.go、python/copilot/client.py剖析底层 RPC 调用链路。读完本文你将掌握在 Node.js/TypeScript、Python、Go、.NET、Java、Rust 六种语言中正确加载、验证与排障插件目录的完整实战方案。何时使用插件目录当你希望做到以下几点时应当优先考虑插件目录把一组能力打包成单个单元分发例如一个 TypeScript reviewer 能力包内含一个 skill、一个强制 lint 的preToolUsehook以及一个运行评审流程的自定义 agent把能力包 vendoring 进仓库让宿主应用的每一次克隆都按确定性加载同一组扩展在本地开发插件之后再将插件发布到 marketplace覆盖或扩展 marketplace 已安装的插件用本地 checkout 进行测试。反之如果只是需要添加单个 MCP server、单个 hook 或单个自定义 agent可以直接通过 SDK 配置mcpServers、hooks、customAgents内联注册。插件目录通常在三个及以上相关扩展需要一起发布时才最具价值。插件文件夹布局Copilot CLI 会扫描每个插件目录寻找plugin.json清单或根目录级的SKILL.md。一个最小化的插件长这样my-plugin/ ├── plugin.json # 清单除非只使用 SKILL.md否则必填 ├── SKILL.md # 可选顶层 skill ├── hooks.json # 可选hooks 配置 ├── .mcp.json # 可选MCP server 配置 ├── agents/ # 可选自定义 agents每个 agent 一个 .md 文件 │ └── code-reviewer.md └── skills/ # 可选额外 skills └── lint-fix/ └── SKILL.md清单还可以放在.github/plugin.json或.github/plugin/plugin.json这样插件可以嵌在既有仓库中而无需改动仓库根布局。每个子系统hooks、MCP、LSP、skills、agents都有各自的加载器并且都是可选的——插件只需包含它实际贡献的部分即可。完整的清单 schema 可参见 CLI 的/plugin斜杠命令所引用的运行时文档。从 SDK 加载插件目录插件目录通过给 Copilot CLI 传入--plugin-dir path加载由 SDK 负责拉起 CLI。各语言通过运行时连接的 extra-args 选项暴露该参数且该参数可以重复传入以加载多个插件。Node.js / TypeScriptimport { CopilotClient, RuntimeConnection } from github/copilot-sdk; async function main() { const client new CopilotClient({ connection: RuntimeConnection.forStdio({ args: [ --plugin-dir, ./plugins/code-reviewer, --plugin-dir, ./plugins/lint-fix, ], }), }); await client.start(); } main();Pythonfrom copilot import CopilotClient, StdioRuntimeConnection client CopilotClient( connectionStdioRuntimeConnection( args( --plugin-dir, ./plugins/code-reviewer, --plugin-dir, ./plugins/lint-fix, ), ), ) await client.start()Goclient : 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 }.NETusing 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();Javavar options new CopilotClientOptions() .setCliArgs(new String[] { --plugin-dir, ./plugins/code-reviewer, --plugin-dir, ./plugins/lint-fix, }); var client new CopilotClient(options); client.start().get();Rustuse 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?;上面的示例使用 stdio 运行时连接——这是 SDK 捆绑 CLI 时的默认方式。如果你通过 URL 连接到外部运行时forUri/ForUri则需要在启动该长驻 CLI server 时自行传入--plugin-dirSDK 不会把--plugin-dir转发给它没有拉起的运行时。这一点在 nodejs/src/client.ts 的启动逻辑中体现得很清楚只有当连接类型不是外部 server 时SDK 才会自己拉起 CLI server 进程并注入 extra args。每会话级插件目录Per-session plugin directories--plugin-dir是启动参数因此它一次性固定了整个 CLI 进程及其上创建的所有会话的插件集合。当不同会话需要不同的插件集合或者 SDK 连接的是一个并非自己拉起的运行时应当把目录放到会话配置中传递。这些目录会随session.create与session.resume的 payload 通过 JSON-RPC 传输而不是作为进程参数因此对于外部运行时也能以与启动选项相同的方式生效。以 Node.js / TypeScript 为例import { CopilotClient } from github/copilot-sdk; const client new CopilotClient(); await client.start(); const session await client.createSession({ pluginDirectories: [./plugins/code-reviewer], });各 SDK 中对应的会话级选项如下SDKSession 选项Node.js / TypeScriptpluginDirectories: string[]Pythonplugin_directories[...]GoPluginDirectories: []string{...}.NETPluginDirectories [...]Java.setPluginDirectories(List.of(...))Rust.with_plugin_directories([...])路径解析规则相对路径会相对于workingDirectory解析若未设置工作目录则相对于运行时的工作目录因此推荐使用绝对路径。无法解析的条目只会被记录日志并跳过而不会导致会话创建失败。该选项是显式 opt-in 的意味着即使enableConfigDiscovery为false插件 agents 和规则也会被加载。以这种方式加载的资源在会话级优先级顺序中位于项目源与个人/主目录源之间。从源码可以看到实现细节nodejs/src/client.ts 在组装session.create请求时把pluginDirectories: config.pluginDirectories直接放入 payloadgo/client.go 同样在会话请求中设置req.PluginDirectories config.PluginDirectoriespython/copilot/client.py 则执行payload[pluginDirectories] plugin_directories。三条实现路径殊途同归插件目录随会话请求体通过 JSON-RPC 到达运行时。受信任的宿主内置插件目录Trusted host-bundled plugin directories对于自带可信插件的应用可以把这些目录注册为客户端启动选项。SDK 会在连接并校验协议之后、start返回或任何会话创建之前把完整的、保序的目录集合发送给运行时。路径必须是绝对路径若该选项未设置或为空数组则完全不会发起 RPC 调用。以 Node.js / TypeScript 为例import { CopilotClient } from github/copilot-sdk; async function main() { const client new CopilotClient({ builtinPluginDirectories: [ /opt/my-app/copilot-plugins/core, /opt/my-app/copilot-plugins/github, ], }); await client.start(); } main();各 SDK 中对应的启动选项如下SDK启动选项Node.js / TypeScriptbuiltinPluginDirectories: string[]Pythonbuiltin_plugin_directories[...]GoBuiltinPluginDirectories: []string{...}.NETBuiltinPluginDirectories [...]Java.setBuiltinPluginDirectories(List.of(Path.of(...)))Rust.with_builtin_plugin_directories([...])这是一个信任边界它只用于宿主应用自己捆绑并控制的插件。它和--plugin-dir有本质区别——后者是 CLI 进程的启动参数用于显式加载普通插件目录。由于该启动选项通过 JSON-RPC 传输而非转发进程参数因此连接既有运行时也同样有效。源码证据非常直接nodejs/src/client.ts构造函数会遍历builtinPluginDirectories用isAbsolute校验每个路径任何非绝对路径都会抛出builtinPluginDirectories must contain only absolute paths: ...错误nodejs/src/client.tsdoStart()在连接 server 并完成协议版本校验之后调用plugins.builtin.setRPC发送{ paths: this.builtinPluginDirectories }失败则forceStop并抛出异常go/client.go 与 python/copilot/client.pyGo 与 Python 实现同样强制执行绝对路径校验go/client.go、python/copilot/client.pyGo 与 Python 也在客户端启动流程中发送plugins.builtin.set请求。插件可以贡献什么加载一个插件目录后其扩展对该客户端创建的每一个会话都可见。运行时会把插件提供的扩展与你在 SDK 内联注册的内容合并在一起插件贡献会话中可见为SkillsSKILL.md、skills/*/SKILL.mdsession.skills.list()中的条目可按名称注入自定义 agentsagents/*.md可通过task(agent_type...)工具调度Hookshooks.json与通过 SDK 注册的 hooks 一起触发MCP servers.mcp.json通过session.mcp.*可访问的工具与资源LSP servers.lsp.json通过session.lsp.initialize(...)初始化插件 agents 是 Fleet Mode 中的一等公民子 agent父 agent 可以按agent_type调度它们运行时也会像对待其他子 agent 一样为它们触发subagentStart/subagentStophooks。插件目录 vs Marketplace 插件运行时存在两种安装插件的方式二者对会话最终呈现的效果相同Marketplace / 直接仓库插件通过 CLI 的/plugin斜杠命令或底层的installedPlugins用户设置持久安装。它们是ambient环境性的——任何针对同一用户配置运行的会话都会看到它们并参与插件发现规则--plugin-dir插件是explicit显式且 ephemeral临时的——只对用该标志启动的那个 CLI 进程生效。它们优先于 ambient 发现并会与具有相同缓存路径的 marketplace 条目去重因此当两种途径都引用同一个插件时不会加载两次。对于 SDK 驱动的应用--plugin-dir通常是更合适的选择它让插件集合始终处于应用的掌控之下而不依赖于每台机器的用户状态。让插件集合具备确定性当宿主机器上可能安装了其他插件marketplace 或个人插件时在运行时环境中设置COPILOT_PLUGIN_DIR_ONLYtrue可以抑制自动插件发现——只有通过--plugin-dir传入的目录会被加载。以 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();这一做法非常适合 CI、无头服务器部署以及任何希望插件集合可复现、不依赖宿主用户配置的场景。检查哪些插件已加载会话创建后可以通过列出活动插件来确认目录是否被正确拾取import { CopilotClient } from github/copilot-sdk; const client new CopilotClient(); await client.start(); const session await client.createSession({ onPermissionRequest: async () ({ kind: approve-once }), }); const plugins await session.rpc.plugins.list(); for (const plugin of plugins.plugins) { console.log(${plugin.name} (${plugin.enabled ? enabled : disabled})); }通过--plugin-dir加载的插件会出现在该列表中其缓存路径cache path被设置为你提供的目录marketplace 安装项则会标记其 registry 来源。故障排查no plugin.json or SKILL.md found in dir—— 目录存在但不满足插件资格。请在根目录或.github/下添加plugin.json清单或放入一个顶层SKILL.md插件已加载但 agents/skills 不可见—— 确保插件清单声明了其贡献的 agents/skills或使用隐式布局agents/*.md、skills/*/SKILL.md。随后调用session.rpc.skills.reload()即可在不重启的情况下拾取变更重复 hooks 触发—— 运行时按cache_path去重但仅当同一个目录同时被引用为 marketplace 安装项和--plugin-dir时才会去重。如果两个不同目录包含同一个插件两者都会加载。请移除其中一个或使用COPILOT_PLUGIN_DIR_ONLYtrue连接外部运行时后--plugin-dir被忽略—— SDK 只在自行拉起 CLI 时才转发 extra args。对于外部运行时forUri/ForUri请把--plugin-dir传给启动该运行时 server 的命令行。延伸阅读自定义 Agents编写随插件agents/目录分发的 agentsSkillsSKILL.md文件的加载方式与 skill 层级排序规则Hooks插件定义的 hooks 与 SDK 注册的 hooks 一起触发MCP Servers插件提供的 MCP servers 与内联注册的集成方式相同Fleet Mode插件提供的 agents 可作为子 agent 调度。【免费下载链接】copilot-sdkMulti-platform SDK for integrating GitHub Copilot Agent into apps and services项目地址: https://gitcode.com/GitHub_Trending/co/copilot-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考