Skills are reusable prompt modules that extend Copilot's capabilities. Load skills from directories to give Copilot specialized abilities for specific domains or workflows.
A skill is a named directory containing a SKILL.md file — a markdown document that provides instructions to Copilot. When loaded, the skill's content is injected into the session context.
Skills allow you to:
- Package domain expertise into reusable modules
- Share specialized behaviors across projects
- Organize complex agent configurations
- Enable/disable capabilities per session
Specify directories containing skills when creating a session:
Node.js / 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: "approved" }),
});
// Copilot now has access to skills in those directories
await session.sendAndWait({ prompt: "Review this code for security issues" });Python
from copilot import CopilotClient
from copilot.types import PermissionRequestResult
async def main():
client = CopilotClient()
await client.start()
session = await client.create_session({
"model": "gpt-4.1",
"skill_directories": [
"./skills/code-review",
"./skills/documentation",
],
"on_permission_request": lambda req, inv: PermissionRequestResult(kind="approved"),
})
# Copilot now has access to skills in those directories
await session.send_and_wait({"prompt": "Review this code for security issues"})
await client.stop()Go
package main
import (
"context"
"log"
copilot "github.com/github/copilot-sdk/go"
)
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) (copilot.PermissionRequestResult, error) {
return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindApproved}, 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.SDK;
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(new PermissionRequestResult { Kind = PermissionRequestResultKind.Approved }),
});
// Copilot now has access to skills in those directories
await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Review this code for security issues"
});Disable specific skills while keeping others active:
Node.js / TypeScript
const session = await client.createSession({
skillDirectories: ["./skills"],
disabledSkills: ["experimental-feature", "deprecated-tool"],
});Python
session = await client.create_session({
"skill_directories": ["./skills"],
"disabled_skills": ["experimental-feature", "deprecated-tool"],
})Go
package main
import (
"context"
copilot "github.com/github/copilot-sdk/go"
)
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) (copilot.PermissionRequestResult, error) {
return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindApproved}, nil
},
})
_ = session
}session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
SkillDirectories: []string{"./skills"},
DisabledSkills: []string{"experimental-feature", "deprecated-tool"},
}).NET
using GitHub.Copilot.SDK;
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(new PermissionRequestResult { Kind = PermissionRequestResultKind.Approved }),
});
}
}var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = new List<string> { "./skills" },
DisabledSkills = new List<string> { "experimental-feature", "deprecated-tool" },
});Each skill is a named subdirectory containing a SKILL.md file:
skills/
├── code-review/
│ └── SKILL.md
└── documentation/
└── SKILL.md
The skillDirectories option points to the parent directory (e.g., ./skills). The CLI discovers all SKILL.md files in immediate subdirectories.
A SKILL.md file is a markdown document with optional YAML frontmatter:
---
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.The frontmatter fields:
name— The skill's identifier (used withdisabledSkillsto selectively disable it). If omitted, the directory name is used.description— A short description of what the skill does.
The markdown body contains the instructions that are injected into the session context when the skill is loaded.
| Language | Field | Type | Description |
|---|---|---|---|
| Node.js | skillDirectories |
string[] |
Directories to load skills from |
| Node.js | disabledSkills |
string[] |
Skills to disable |
| Python | skill_directories |
list[str] |
Directories to load skills from |
| Python | disabled_skills |
list[str] |
Skills to disable |
| Go | SkillDirectories |
[]string |
Directories to load skills from |
| Go | DisabledSkills |
[]string |
Skills to disable |
| .NET | SkillDirectories |
List<string> |
Directories to load skills from |
| .NET | DisabledSkills |
List<string> |
Skills to disable |
-
Organize by domain - Group related skills together (e.g.,
skills/security/,skills/testing/) -
Use frontmatter - Include
nameanddescriptionin YAML frontmatter for clarity -
Document dependencies - Note any tools or MCP servers a skill requires
-
Test skills in isolation - Verify skills work before combining them
-
Use relative paths - Keep skills portable across environments
Skills work alongside custom agents:
const session = await client.createSession({
skillDirectories: ["./skills/security"],
customAgents: [{
name: "security-auditor",
description: "Security-focused code reviewer",
prompt: "Focus on OWASP Top 10 vulnerabilities",
}],
onPermissionRequest: async () => ({ kind: "approved" }),
});Skills can complement MCP server capabilities:
const session = await client.createSession({
skillDirectories: ["./skills/database"],
mcpServers: {
postgres: {
type: "local",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
tools: ["*"],
},
},
onPermissionRequest: async () => ({ kind: "approved" }),
});- Check path exists - Verify the skill directory path is correct and contains subdirectories with
SKILL.mdfiles - Check permissions - Ensure the SDK can read the directory
- Check SKILL.md format - Verify the markdown is well-formed and any YAML frontmatter uses valid syntax
- Enable debug logging - Set
logLevel: "debug"to see skill loading logs
If multiple skills provide conflicting instructions:
- Use
disabledSkillsto exclude conflicting skills - Reorganize skill directories to avoid overlaps
- Custom Agents - Define specialized AI personas
- Custom Tools - Build your own tools
- MCP Servers - Connect external tool providers