概述
技能是一个具有名称的目录,其中包含一个 SKILL.md 文件——这是一份向 Copilot 提供指令的 Markdown 文档。 加载后,技能的内容将注入到会话上下文中。
技能允许您:
- 将域专业知识打包到可重用模块中
- 跨项目共享特定行为
- 整理复杂的代理配置
- 每个会话启用/禁用功能
加载技能
创建会话时,指定包含技能的目录:
TypeScript
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
model: "gpt-4.1",
skillDirectories: [
"./skills/code-review",
"./skills/documentation",
],
onPermissionRequest: async () => ({ kind: "approve-once" }),
});
// Copilot now has access to skills in those directories
await session.sendAndWait({ prompt: "Review this code for security issues" });
Python
from copilot import CopilotClient, PermissionDecisionApproveOnce
async def main():
client = CopilotClient()
await client.start()
session = await client.create_session(
on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
model="gpt-4.1",
skill_directories=[
"./skills/code-review",
"./skills/documentation",
],
)
# Copilot now has access to skills in those directories
await session.send_and_wait("Review this code for security issues")
await client.stop()
Go
package main
import (
"context"
"log"
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/rpc"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
SkillDirectories: []string{
"./skills/code-review",
"./skills/documentation",
},
OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionApproveOnce{}, nil
},
})
if err != nil {
log.Fatal(err)
}
// Copilot now has access to skills in those directories
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
Prompt: "Review this code for security issues",
})
if err != nil {
log.Fatal(err)
}
}
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
SkillDirectories = new List<string>
{
"./skills/code-review",
"./skills/documentation",
},
OnPermissionRequest = (req, inv) =>
Task.FromResult(PermissionDecision.ApproveOnce()),
});
// Copilot now has access to skills in those directories
await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Review this code for security issues"
});
Java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;
import java.util.List;
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setSkillDirectories(List.of(
"./skills/code-review",
"./skills/documentation"
))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
// Copilot now has access to skills in those directories
session.sendAndWait(new MessageOptions()
.setPrompt("Review this code for security issues")
).get();
}
禁用技能
禁用特定技能,同时使其他人保持活动状态:
TypeScript
const session = await client.createSession({
skillDirectories: ["./skills"],
disabledSkills: ["experimental-feature", "deprecated-tool"],
});
Python
from copilot.session import PermissionHandler
session = await client.create_session(
on_permission_request=PermissionHandler.approve_all,
skill_directories=["./skills"],
disabled_skills=["experimental-feature", "deprecated-tool"],
)
Go
package main
import (
"context"
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/rpc"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
SkillDirectories: []string{"./skills"},
DisabledSkills: []string{"experimental-feature", "deprecated-tool"},
OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionApproveOnce{}, nil
},
})
_ = session
}
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
SkillDirectories: []string{"./skills"},
DisabledSkills: []string{"experimental-feature", "deprecated-tool"},
})
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;
public static class SkillsExample
{
public static async Task Main()
{
await using var client = new CopilotClient();
var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = new List<string> { "./skills" },
DisabledSkills = new List<string> { "experimental-feature", "deprecated-tool" },
OnPermissionRequest = (req, inv) =>
Task.FromResult(PermissionDecision.ApproveOnce()),
});
}
}
var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = new List<string> { "./skills" },
DisabledSkills = new List<string> { "experimental-feature", "deprecated-tool" },
});
Java
import com.github.copilot.rpc.*;
import java.util.List;
var session = client.createSession(
new SessionConfig()
.setSkillDirectories(List.of("./skills"))
.setDisabledSkills(List.of("experimental-feature", "deprecated-tool"))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
技能目录结构
每个技能都是一个包含 SKILL.md 文件的命名子目录:
skills/
├── code-review/
│ └── SKILL.md
└── documentation/
└── SKILL.md
选项 skillDirectories 指向父目录(例如 ./skills)。 CLI 可发现即时子目录中的所有 SKILL.md 文件。
SKILL.md 格式
SKILL.md文件是一个具有可选 YAML 头部信息的 Markdown 文件:
---
name: code-review
description: Specialized code review capabilities
---
# Code Review Guidelines
When reviewing code, always check for:
1. **Security vulnerabilities** - SQL injection, XSS, etc.
2. **Performance issues** - N+1 queries, memory leaks
3. **Code style** - Consistent formatting, naming conventions
4. **Test coverage** - Are critical paths tested?
Provide specific line-number references and suggested fixes.
"前置信息字段:"
name:技能的标识符(与disabledSkills一起使用,用于选择性地禁用该技能)。 如果省略,则使用目录名称。description:简要说明技能的作用。
Markdown 正文包含加载技能时注入到会话上下文的说明。
配置选项
SessionConfig 技能字段
| 语言 | 领域 | 类型 | Description |
|---|---|---|---|
| Node.js | skillDirectories | string[] | 要从中加载技能的目录 |
| Node.js | disabledSkills | string[] | 禁用技能 |
| Python | skill_directories | list[str] | 要从中加载技能的目录 |
| Python | disabled_skills | list[str] | 禁用技能 |
| Go | SkillDirectories | []string | 要从中加载技能的目录 |
| Go | DisabledSkills | []string | 禁用技能 |
| .NET | SkillDirectories | List<string> | 要从中加载技能的目录 |
| .NET | DisabledSkills | List<string> | 禁用技能 |
最佳做法
-
按域组织 - 将相关技能组合在一起(例如,
skills/security/``skills/testing/) -
使用前置元数据 - 在 YAML 前置元数据中包含
name和description,以提高清晰度 -
文档依赖项 - 记下技能所需的任何工具或 MCP 服务器
-
单独测试技能 - 在将技能组合起来之前,先确认各项技能可正常运行
-
使用相对路径 - 使技能在环境中可移植
与其他功能结合使用
技能 + 自定义代理
代理 skills 字段中列出的技能 是预先加载的—其完整内容在启动时注入到代理的上下文中,因此代理可以立即访问技能说明,而无需调用技能工具。 技能名称从会话级 skillDirectories 中解析。
const session = await client.createSession({
skillDirectories: ["./skills/security"],
customAgents: [{
name: "security-auditor",
description: "Security-focused code reviewer",
prompt: "Focus on OWASP Top 10 vulnerabilities",
skills: ["security-scan", "dependency-check"],
}],
onPermissionRequest: async () => ({ kind: "approve-once" }),
});
注意
技能为可选启用项——省略 skills 时,不会注入任何技能内容。 子代理不从父级继承技能;必须为每个代理显式列出它们。
技能 + MCP 服务器
技能可以补充 MCP 服务器功能:
const session = await client.createSession({
skillDirectories: ["./skills/database"],
mcpServers: {
postgres: {
type: "local",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
tools: ["*"],
},
},
onPermissionRequest: async () => ({ kind: "approve-once" }),
});
故障排除
技能未加载
- 检查路径是否存在 - 验证技能目录路径是否正确,并且包含包含
SKILL.md文件的子目录 - 检查权限 - 确保 SDK 可以读取目录
- 检查 SKILL.md 格式 - 验证 markdown 格式正确,并且任何 YAML frontmatter 都使用有效的语法
- 启用调试日志 - 将
logLevel: "debug"设为开启以查看技能加载日志
技能冲突
如果多个技能提供冲突的说明:
- 使用
disabledSkills来排除冲突技能 - 重新组织技能目录以避免重叠
另见
- 构建你的第一个由 Copilot 提供支持的应用 - 定义专用 AI 角色
- 构建你的第一个由 Copilot 提供支持的应用 - 生成自己的工具
- Using MCP servers with the GitHub Copilot SDK - 连接外部工具提供方