Custom skills
Skills are reusable prompt modules that extend Copilot’s capabilities. Load skills from directories to give Copilot specialized abilities for specific domains or workflows.
Overview
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
Loading skills
Specify directories containing skills when creating a session:
Node.js / TypeScript
```typescript
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
model: "gpt-5.4",
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
```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-5.4",
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
```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-5.4",
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
```csharp
using GitHub.Copilot;
using GitHub.Copilot.Rpc;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5.4",
SkillDirectories = new List
{
"./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"
});
```
</details>
Java
```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-5.4")
.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();
}
```
## Disabling skills
Disable specific skills while keeping others active:
Node.js / TypeScript
```typescript
const session = await client.createSession({
skillDirectories: ["./skills"],
disabledSkills: ["experimental-feature", "deprecated-tool"],
});
```
Python
```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
```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
}
```
```go
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
SkillDirectories: []string{"./skills"},
DisabledSkills: []string{"experimental-feature", "deprecated-tool"},
})
```
.NET
```csharp
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 { "./skills" },
DisabledSkills = new List { "experimental-feature", "deprecated-tool" },
OnPermissionRequest = (req, inv) =>
Task.FromResult(PermissionDecision.ApproveOnce()),
});
}
}
```
```csharp
var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = new List { "./skills" },
DisabledSkills = new List { "experimental-feature", "deprecated-tool" },
});
```
</details>
Java
```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 directory structure
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.
### SKILL.md format
A `SKILL.md` file is a markdown document with optional YAML frontmatter:
```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.
```
The frontmatter fields:
* **`name`**: The skill's identifier (used with `disabledSkills` to 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.
## Configuration options
### SessionConfig skill fields
| 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` | Directories to load skills from |
| .NET | `DisabledSkills` | `List` | Skills to disable |
## Best practices
1. **Organize by domain** - Group related skills together (e.g., `skills/security/`, `skills/testing/`)
1. **Use frontmatter** - Include `name` and `description` in YAML frontmatter for clarity
1. **Document dependencies** - Note any tools or MCP servers a skill requires
1. **Test skills in isolation** - Verify skills work before combining them
1. **Use relative paths** - Keep skills portable across environments
## Combining with other features
### Skills + custom agents
Skills listed in an agent's `skills` field are **eagerly preloaded**—their full content is injected into the agent's context at startup, so the agent has access to the skill instructions immediately without needing to invoke a skill tool. Skill names are resolved from the session-level `skillDirectories`.
```typescript
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" }),
});
```
> [!NOTE]
> Skills are opt-in—when `skills` is omitted, no skill content is injected. Sub-agents do not inherit skills from the parent; you must list them explicitly per agent.
### Skills + MCP servers
Skills can complement MCP server capabilities:
```typescript
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" }),
});
```
## Troubleshooting
### Skills not loading
1. **Check path exists** - Verify the skill directory path is correct and contains subdirectories with `SKILL.md` files
1. **Check permissions** - Ensure the SDK can read the directory
1. **Check SKILL.md format** - Verify the markdown is well-formed and any YAML frontmatter uses valid syntax
1. **Enable debug logging** - Set `logLevel: "debug"` to see skill loading logs
### Skill conflicts
If multiple skills provide conflicting instructions:
* Use `disabledSkills` to exclude conflicting skills
* Reorganize skill directories to avoid overlaps
## See also
* [Custom Agents](/copilot-sdk/getting-started.html#create-custom-agents) - Define specialized AI personas
* [Custom Tools](/copilot-sdk/getting-started.html#step-4-add-a-custom-tool) - Build your own tools
* [MCP Servers](/copilot-sdk/features/mcp.html) - Connect external tool providers