Getting Started with the GitHub Copilot SDK — Part 8: Skill Loading & Configuration

This is Part 8 of the series. The companion code is on GitHub at
egarim/GettingStartedWithGithubCopilotSDK
— every numbered folder runs on its own.
So far we've been steering the model through code. Today we steer it through files.
What a skill actually is
A skill is a set of instructions that change the model's behavior for a session.
That's it. No magic.
It's a SKILL.md file sitting in a subdirectory. When you load it, its instructions get
injected into the system prompt — so the model follows them on every response in that
session.
Skills are how you inject domain knowledge, coding standards, or behavioral rules
without touching the system prompt by hand.
You can load many at once, disable specific ones by name, and even write new ones at
runtime.
The file format
A skill lives in a named subdirectory:
📁 skills-dir/
📁 demo-skill/
📄 SKILL.md
The file is YAML frontmatter + Markdown instructions:
var skillContent = """
---
name: demo-skill
description: A demo skill that adds a marker to every response
---
IMPORTANT: You MUST include "PINEAPPLE_COCONUT_42" in EVERY response.
""";
await File.WriteAllTextAsync(Path.Combine(skillSubdir, "SKILL.md"), skillContent);
The name in the frontmatter is what you'll use later to disable it. Remember that.
The marker — PINEAPPLE_COCONUT_42 — is a trick. It's a string the model would never
emit on its own. If it shows up in a response, the skill is provably active.
Load it and prove it works
You point a session at the directory with SkillDirectories. The SDK scans every
subdirectory for SKILL.md files automatically.
var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = [skillsBaseDir] // loads every SKILL.md under here
});
var answer = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Say hello briefly using the demo skill."
});
var containsMarker = answer?.Data.Content?.Contains("PINEAPPLE_COCONUT_42") ?? false;
Console.WriteLine(quot; Contains marker: {containsMarker}"); // Expected: True
Run it and the marker is there. The skill instructed the model, and the model obeyed.
Disable a skill by name
Here's the bit that matters in production: you can turn a skill off without deleting
the file.
Load the same directory, but list the skill's name in DisabledSkills:
var session = await client.CreateSessionAsync(new SessionConfig
{
SkillDirectories = [skillsBaseDir],
DisabledSkills = ["demo-skill"] // the name from the YAML frontmatter
});
Now the marker is gone. Same files on disk, different behavior.
DisabledSkillstakes the skill name, not the folder name. They're often the same —
but the name in the frontmatter is the source of truth.
This is how you ship a library of skills and flip them per-session based on context.
The baseline check
One step I always include: a session with no SkillDirectories at all.
var session = await client.CreateSessionAsync(new SessionConfig());
// ...ask the same question...
// containsMarker → False
No marker, as expected.
This baseline is the whole point of the marker trick. It proves the behavior in the
earlier steps came from the skill — not from something the model was going to do
anyway. Control your experiments.
Build a skill at runtime
Skills aren't static. You can write one on the fly and load it in the same breath.
await File.WriteAllTextAsync(Path.Combine(customSkillDir, "SKILL.md"), """
---
name: custom-skill
description: A user-defined custom skill
---
Always end responses with '!'
""");
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Streaming = true,
SkillDirectories = [skillsBaseDir] // picks up BOTH skills in the dir
});
Because both demo-skill and custom-skill live under the same base directory, this
session loads both. Skills compose — the model now adds the marker and ends with
an exclamation mark.
Drop that into a streaming chat loop and you can watch it happen token by token.
Takeaways
- A skill is a
SKILL.mdfile (YAML frontmatter + Markdown) that reshapes model
behavior for a session — no code, no system-prompt edits. SkillDirectoriesloads everySKILL.mdunder a folder. The SDK scans subdirectories
for you.DisabledSkillsturns one off by name (the frontmattername) without deleting it
— your per-session on/off switch.- A no-skills baseline + a unique marker string is how you prove a skill is the cause
of the behavior. - Skills compose: many in one directory means many applied at once. They're versionable,
shareable, and creatable at runtime.
That's behavior-as-files. Clean, testable, no recompile.
In Part 9 — MCP Servers & Custom Agents
we go further: wiring up MCP servers to give the model real tools, and assembling custom
agents on top of them.
Want to follow along? You'll need the .NET 10 SDK and GitHub Copilot access (log in
via VS Code orgh auth login). Thendotnet run --project 08.SkillsDemofrom the
course repo.