GitHub Copilot Skills: Transform AI into a Domain Expert
Tools

GitHub Copilot Skills: Transform AI into a Domain Expert

Learn to create, manage, and leverage GitHub Copilot Agent Skills with SKILL.md. Real workflows, practical examples, and how to make AI understand your project.

Por Omar Flores
#github-copilot #ai #developer-tools #developer-workflow #productivity #vscode #automation

Imagine you hire a brilliant new engineer for your team. They write code fast, they never complain, they’re available at any hour. But every morning they arrive with no memory of the day before. They don’t know your naming conventions. They don’t know you use DDD. They don’t remember that integration tests live in /test/integration/ and not in the root. Every conversation starts from scratch.

That’s Copilot without context.

The tool is there. The model has capability. Without structure to guide it, though, you end up repeating the same instructions every session, every task. What should be a productivity multiplier becomes an expensive autocomplete with the memory of a goldfish.

Agent Skills are the answer to that problem. Not a trick — a mechanism for teaching Copilot exactly what to do when it faces specific tasks in your domain. And doing it right from the first prompt.


AI Without Context Is Just Expensive Autocomplete

GitHub Copilot has four mechanisms for customizing its behavior, and confusing them is one of the most common mistakes I see in teams starting to integrate AI into their workflow:

Custom Instructions (.github/copilot-instructions.md) define coding standards that always apply. Project conventions, naming rules, style preferences. They are permanent, low-volume instructions that the agent reads with every request. Use them for things like: “this project uses Go 1.25, interfaces go in the domain package, and errors are wrapped with fmt.Errorf”.

Prompt Files (.github/prompts/*.prompt.md) are automated tasks you invoke manually. Scaffolding a component, preparing a pull request, generating a change summary. Lightweight, single-task at a time.

Custom Agents (.github/agents/*.agent.md) are specialized personas: the security reviewer, the data architect, the testing expert. They control available tools, model choice, and full end-to-end behavior.

Agent Skills are the middle layer that gets the most underestimated. They are folders of instructions, scripts, and resources that Copilot loads on demand when the task is relevant. Unlike custom instructions that are always active, a skill only consumes context when the agent needs it. Unlike a prompt file, it can include supporting files: templates, scripts, input/output examples.

The key question is: when does each one apply?

NeedMechanism
Permanent project rulesCustom Instructions
One-off repeatable taskPrompt File
Specialized personaCustom Agent
Reusable capability with resourcesAgent Skill

When you want Copilot to know how to run and debug your integration tests, or how to prepare a release following your specific process, or how to review code with your team’s exact criteria — that’s skill territory.


What an Agent Skill Actually Is

A skill is a folder with a SKILL.md file at its root. It can also include scripts, templates, and examples. The system follows an open standard documented at agentskills.io, which means skills you create in VS Code also work in GitHub Copilot CLI and the Copilot cloud agent.

Portability matters. If your team uses Copilot from the terminal for automation tasks, and another developer uses it from VS Code for code review, the same skill works in both environments without modification.

Skills are stored in two places:

# Project skills (in your repository)
.github/skills/
.claude/skills/
.agents/skills/

# Personal skills (in your user profile)
~/.copilot/skills/
~/.claude/skills/
~/.agents/skills/

The distinction matters from day one. A project skill travels with the code: any developer who clones the repo has access to it. A personal skill is yours, applies across all your projects, and no one else on the team has it by default.

For a team, the clear convention is: project workflow skills go in .github/skills/, personal preference skills go in ~/.copilot/skills/.


The Progressive Loading Model

Here is the detail that separates skills from a simple instructions system: Copilot does not load all the content of all installed skills for every conversation. Skills use a three-level model that keeps context efficient even when you have dozens installed.

Level 1: Discovery. Copilot reads only the name and description from the YAML frontmatter of each skill. Nothing else. From that metadata it decides whether a skill is relevant to your current request. If you ask “help me debug this GitHub Action failing in CI”, Copilot matches that intent to the description of your github-actions-debugging skill.

Level 2: Instructions. If there is a match, Copilot loads the body of the SKILL.md — the detailed instructions, the step-by-step procedures, the criteria. This is the content that guides the agent’s behavior for that task.

Level 3: Resources. As the agent works through the instructions, it accesses additional files in the skill directory only when it needs them: supporting scripts, templates, examples. If a file is not referenced in the instructions, it never gets loaded.

This design has a direct consequence: you can install 30 skills without impacting the performance of everyday tasks. The context cost is proportional to the work you’re doing, not the number of skills installed.

The frontmatter description is the loading contract. A vague description produces uncertain matches. A precise description produces exact invocations.


Creating Your First Skill from Scratch

The process starts with the folder structure. The directory name must match the name field in the frontmatter exactly. If they don’t match, the skill fails silently — no error, no warning. Just doesn’t appear and doesn’t load. One of the most frustrating things to debug.

.github/skills/
└── api-integration-testing/
    ├── SKILL.md
    ├── test-template.http
    └── examples/
        ├── auth-test.http
        └── pagination-test.http

Now the SKILL.md. The frontmatter has these fields:

---
name: api-integration-testing
description: >
  Skill for designing, running, and debugging integration tests for REST APIs.
  Use it when creating end-to-end test cases, verifying response contracts, or
  debugging failures in existing integration tests. Includes templates and
  examples for authentication and pagination scenarios.
argument-hint: "[endpoint or module to test] [test type: smoke | contract | load]"
user-invocable: true
disable-model-invocation: false
---

The description field is the most important of the five. It must describe two things: what the skill does, and when to use it. The agent uses this to decide whether the skill applies to your request. A single-sentence description is not enough.

The argument-hint field appears as placeholder text in the chat input when you invoke the skill as a slash command. It guides the user on what additional context to provide.

user-invocable: true (default) makes the skill appear in the / chat menu. disable-model-invocation: true means the skill is only invoked manually and never by automatic model inference.

The body of the SKILL.md contains the instructions Copilot will follow. Write them as if you’re explaining the process to a senior developer who doesn’t know your specific project:

# API Integration Testing

## When to use this skill

When creating integration tests for REST endpoints, verifying authentication
behavior, or debugging a test that fails intermittently in CI.

## Test design process

Before writing code, identify:

1. The expected endpoint contract (status codes, response structure)
2. Edge cases: empty payload, invalid auth, rate limits
3. Execution order if there are dependencies between tests

For test structure, use the [base template](./test-template.http) included
in this skill.

## Debugging CI failures

When a test passes locally but fails in CI:

1. Check environment variables — most environment failures come from config
2. Review execution order if there is shared state between tests
3. Look for time dependencies: hardcoded sleeps or insufficient timeouts

## Reference examples

The [auth examples](./examples/auth-test.http) and [pagination examples](./examples/pagination-test.http)
demonstrate the most common patterns in the project.

The detail that makes the biggest difference in the body: concrete steps. Not “check environment variables”. But “most CI environment failures come from configs that aren’t in the pipeline’s secret manager”. That specificity is what turns a skill into a colleague with real experience.


Workflows Where a Skill Makes a Real Difference

I’ve seen three categories where skills deliver the highest return on configuration time:

Testing and QA. Every project has its own test conventions: which directory, which runner, which naming patterns, which fixtures. A testing skill can include the test template, the exact commands to run partial or full suites, and the debugging process when something fails. The agent knows all of this without you repeating it.

CI/CD and GitHub Actions. Debugging a workflow that fails in CI requires knowing your pipeline’s specific structure. A GitHub Actions debugging skill can include the commands to view logs, the most common failure reasons in your setup, and the process to reproduce the environment locally. A well-crafted skill here beats a Stack Overflow search in terms of speed.

Code review with team criteria. The review rules your team follows are rarely written in a way Copilot knows by default. A code review skill can include the team’s checklist, the anti-patterns specific to your stack, and the non-negotiable approval criteria. The result is consistent reviews that genuinely reflect team standards.

For the code review case, a well-designed skill looks like this:

# Code Review Checklist

## Non-negotiable criteria

Reject any PR that:

- Exposes credentials or secrets in source code
- Has business logic in HTTP handlers (must live in use cases)
- Has no tests for the happy path of new behavior

## Improvement criteria (suggestion, not blocker)

Suggest changes when:

- A function exceeds 40 lines without obvious responsibility separation
- There is duplicated error handling that could be unified
- A variable name takes more than 3 seconds to understand

Invocation Controls

Skills have two invocation mechanisms worth understanding before you ship your first one.

Automatic invocation by the model. By default, Copilot reads the descriptions of all installed skills and decides which ones to load based on your request. You don’t have to do anything. If your message semantically corresponds to a skill’s description, the agent loads it into context before responding.

Manual invocation as a slash command. Type / in the chat input and you see a list of all available skills as commands. You can add context after the name: /api-integration-testing for the payments endpoint in checkout is a valid prompt that invokes the skill and passes it specific information.

The frontmatter fields control the behavior:

user-invocabledisable-model-invocationResult
true (default)false (default)Shows in / and model loads it automatically
falsefalseModel loads it automatically, but doesn’t show in /
truetrueOnly shows in /, model never loads it automatically
falsetrueEffectively disabled

For background knowledge skills — your ORM conventions, your architecture patterns — user-invocable: false is the right configuration. For skills that require specific developer context — which endpoint to test, which PR to review — disable-model-invocation: true makes more sense: the agent won’t load it for irrelevant tasks.


Managing and Sharing Skills

Project skills live in .github/skills/ and enter version control with the code. This has an implication many teams don’t initially consider: when someone on DevOps improves the deployment skill, every developer gets the updated version on their next git pull. Skills evolve with the project.

Personal skills in ~/.copilot/skills/ are portable between projects but not shared. Useful for personal workflows — how you prefer to do debugging, what process you follow for a feature branch — that aren’t team standards but save you from repetition.

For teams that want to share skills without including them in the project repository, there’s the VS Code extension route: an extension can contribute skills using the chatSkills field in its package.json, pointing to the folder with the SKILL.md.

The community has also built a public collection of skills in the github/awesome-copilot repository. Before building a skill from scratch, check whether one already exists for your use case. Adopting it is straightforward: copy the skill directory to your .github/skills/, review the SKILL.md to adapt it to your project, and you have a reusable capability already proven by the community.


What Makes a Skill Actually Useful

I’ve seen skills used in every session and skills installed and never invoked. The difference isn’t the topic — it’s the quality of the description and the specificity of the instructions.

The description as loading contract. The discovery-level model reads only name and description. If the description says “skill for testing”, the agent can’t know whether it applies to unit tests, integration tests, load tests, or none of the above. An effective description mentions the type of task, the context where it applies, and the signals in the user’s request that should trigger the skill.

A weak description:

description: "Skill for integration testing"

An effective description:

description: >
  Skill for creating, running, and debugging REST API integration tests.
  Activates when the user mentions integration testing, endpoint testing,
  HTTP contract verification, or debugging tests that fail in CI.
  Includes templates and examples for authentication and pagination tests.

Instructions with concrete steps. The skill body is not a README. It’s a protocol. Each section should have numbered steps when order matters, decision criteria when there are options, and references to supporting files when they exist.

Supporting files explicitly referenced. The progressive loading model only accesses files in the skill directory that have Markdown links in the SKILL.md. A template without a link never gets loaded. Verify that every supporting file you include has its corresponding reference in the body.


Common Mistakes That Kill a Skill’s Value

The most frequent mistake I’ve encountered: the directory name doesn’t match the name field in the frontmatter. The skill fails silently — no error, no warning. It simply doesn’t appear and doesn’t load. Always verify that directory my-skill/ has exactly name: my-skill in the YAML.

The second mistake: duplicating in the skill what’s already in your custom instructions. If your project has style rules in copilot-instructions.md, don’t copy them to the code review skill. The skill should add specialized behavior, not repeat the permanent context. Duplication raises the token cost without adding value.

The third mistake: creating a skill too generic to compete with the model’s base knowledge. “Skill for writing clean code” doesn’t teach anything Copilot doesn’t already know. A skill adds value when it captures knowledge specific to your project, your stack, or your process. The more specific, the more useful.

A fourth mistake that surfaces in larger teams: unmaintained skills. A skill that instructs on an old version of your API, or references a script that no longer exists, produces incorrect behavior. Skills need the same maintenance cycle as test code: if the project changes, the skill changes.


A skill is not documentation. It’s packaged behavior. The difference is that documentation gets read by a human when they look for it. A skill gets used by the AI when it needs it — without anyone having to ask.