A couple of weeks ago I wrote about building your first custom agent in Copilot CLI, and the example was a read-only Bicep reviewer. It worked, and I’ve kept using it. But I made a mistake in how I set it up: I put our whole tagging standard into the agent’s prompt body. Every allowed tag value, every resource type that can’t be tagged, the lot. That meant every single run of that agent loaded a wall of tagging rules into context, even when I’d asked it to look at API versions and didn’t care about tags at all. The standard changed in October, I updated the agent, and then found I’d also pasted the same rules into two other prompts I’d forgotten about.
Skills are the fix for that. GitHub added Agent Skills support to Copilot in December 2025, and the CLI picked it up straight away. This post is the companion to the custom agent one: what a skill is, where the file goes, and a real run on CLI 1.0.105 so you can see what it looks like when it works.
What a skill is and how it differs from an agent#
A skill is a folder with a SKILL.md file in it. The file has a small YAML header with a name and a description, and the body is instructions in markdown. Anything else you put in the folder, scripts, reference documents, templates, example files, gets picked up alongside the instructions when the skill is used.
The important word is “when”. A skill is not loaded at the start of every session. Copilot reads the description of every skill it can find, and only pulls a skill’s full content into context when your prompt looks like a match, or when you name it explicitly. That is the whole difference from custom instructions, which are always on, and the reason my tagging standard belongs in a skill and not in copilot-instructions.md or an agent body. GitHub’s own guidance says the same thing: short rules that apply to almost everything go in custom instructions, detailed stuff that only matters sometimes goes in a skill.
Against custom agents the line is blurrier, and I’ve gone back and forth on it. An agent is a persona with a tool list: who Copilot is pretending to be and what it’s allowed to touch. A skill is knowledge: how to do one specific thing well. My Bicep reviewer agent should stay thin and say “review Bicep files, read-only”. The tagging rules, the naming convention, the list of API versions we’ve agreed on, each of those is a skill the agent can reach for.
The format is also an open standard. GitHub’s concept page links to the Agent Skills specification repo and says it is “used by a range of different AI systems”, which in practice means the same SKILL.md works in Claude Code, Codex and Copilot. More on why that matters in a minute.
Where the folder goes#
Copilot CLI looks in a fixed set of places. For a skill that belongs to one repo and should travel with it, use one of .github/skills, .claude/skills or .agents/skills in the repo root. For a skill you want in every project, use ~/.copilot/skills or ~/.agents/skills in your home directory. Each skill is its own subdirectory, named in lowercase with hyphens, and the file inside must be called exactly SKILL.md.
If you run copilot skill --help it prints those locations plus two more: skills bundled in installed plugins, and custom directories you’ve added with copilot skill add. There’s no organisation-level location in the docs I read, unlike custom agents which have the .github-private route.
The .claude/skills and .agents/skills entries are the ones I’d draw your attention to. When I ran copilot skill list on my machine the personal section was full of skills I’d never written for Copilot at all. They were the ones Claude Code and Codex had put in ~/.agents/skills, and Copilot had found them and was offering them up. If you’ve already invested in skills for another tool, you probably don’t need to do anything to use them here.
Building one: the tagging standard#
Here’s the skill I built to replace the paragraph I’d been pasting around. The folder is .github/skills/bicep-tagging-review and it holds two files.
The SKILL.md:
---
name: bicep-tagging-review
description: Reviews Bicep files against our tagging standard. Use when asked to check tags, tagging, or tag compliance in Bicep.
---
Our tagging standard requires every taggable resource to carry these tags:
- `environment` (one of dev, test, prod)
- `owner` (an email address)
- `costCentre` (a four digit code)
Read `tagging-standard.md` in this skill's directory for the full rules
and the list of resource types that cannot be tagged.
When asked to review, read every `.bicep` file in the working directory and
report, one line per finding, in the form `file:line: problem`. Do not edit
any files. If everything passes, say so in one line.And next to it, tagging-standard.md, which is the document that actually changes when the standard does:
# Tagging standard
Required tags on every taggable resource: environment, owner, costCentre.
Values:
- environment: dev | test | prod (lowercase)
- owner: a valid email address
- costCentre: exactly four digits
Resource types that cannot be tagged and must be skipped:
- Microsoft.Resources/deployments
- Microsoft.Network/networkSecurityGroups/securityRules
- Microsoft.Authorization/roleAssignmentsTwo fields in the header are required, name and description. The name has to be lowercase with hyphens and normally matches the directory. The description is doing two jobs, which is why it has that slightly odd second sentence. The first half says what the skill does; the second half, “Use when asked to check tags, tagging, or tag compliance”, is there for Copilot’s matching, so it knows which prompts should trigger it. Write that half with the words you actually type, not the words you’d put in a design document.
There are two optional fields. license is just a string describing the licence the skill is under, useful if you publish it. allowed-tools lists tools the skill may use without asking you first, and the docs are blunt about it: only pre-approve shell or bash if you’ve read the skill and any scripts it references and trust where it came from. My skill has neither field. It only reads files, and I’d rather be asked.
The split between the two files is the point of the exercise. SKILL.md says how to behave. tagging-standard.md is the source of truth, and it’s a plain markdown file the platform team can edit in a PR without touching a single instruction to the model. When the standard moved in October, this would have been a one-file change.
Running it#
I dropped a deliberately wrong main.bicep next to it. A storage account with environment: 'Production' (should be prod), an owner of 'platform team' rather than an email, no costCentre, and a Log Analytics workspace with no tags at all.
First, check Copilot can see the skill:
copilot skill listMine printed a Project skills: section with one line, bicep-tagging-review followed by the description, then the personal, plugin and built-in sections underneath. If your skill isn’t in that list, the usual culprits are the file being called skill.md in lowercase or the folder being one level too deep.
Then run it. You can name the skill in the prompt with a slash, or just describe the task and let the description do the matching. I tried both:
copilot -p "Use the /bicep-tagging-review skill on main.bicep" --allow-tool='read' --trust-folder -scopilot -p "Check the tags in main.bicep" --allow-tool='read' --trust-folder -sThe second one is the real test, because there’s no mention of the skill, and here’s what came back from it:
main.bicep:10: `environment` must be `dev`, `test`, or `prod`; `Production` is invalid.
main.bicep:11: `owner` must be a valid email address; `platform team` is invalid.
main.bicep:4: Taggable resource `sa` is missing the required `costCentre` tag.
main.bicep:14: Taggable resource `law` is missing the required `environment`, `owner`, and `costCentre` tags.Every finding is right, and the environment one shows it read tagging-standard.md and not just the summary in SKILL.md, because the “lowercase” rule only lives in the standard document. The explicit /bicep-tagging-review run gave the same four problems split over six lines. Both took well under a minute.
On the flags: -p runs a single prompt and exits, -s prints only the answer, and --trust-folder saves the first-run prompt about trusting the directory. I used --allow-tool='read' rather than --allow-all-tools because the skill only needs to read, and for a non-interactive run that’s the narrower option. If you later add a script to a skill you’ll need to allow shell as well, and that’s the moment to read what the script does.
In an interactive session, /skills gives you a menu where you can enable or disable each one, /skills info bicep-tagging-review shows where it was loaded from, and /skills reload picks up a file you’ve just edited without restarting. There’s also /skills add for pointing at a folder somewhere else on disk.
Installing someone else’s#
You don’t have to write them all yourself. GitHub maintains a community set in the github/awesome-copilot repo with a browsable list at awesome-copilot.github.com/skills, and Anthropic’s anthropics/skills repo works too because of the shared format.
Installation is just copying the folder into one of the locations above and running /skills reload, or from a terminal:
copilot skill add <file, URL or directory>The docs also mention a gh skill extension in GitHub CLI for searching, installing and publishing skills. I couldn’t verify that one. My gh is 2.83.1 and reports unknown command "skill", so either it needs a newer release or it’s an extension I don’t have. Treat it as documented but untested by me.
Whatever route you use, read the SKILL.md and anything it references before you turn it on, and especially before you allow shell. A skill is a prompt injection that you’ve invited in. Most are harmless and useful. The habit of reading them first is cheap.
Caveats#
The CLI docs for copilot skill say you can list, add, enable and disable from the terminal, and that remove is also available, but give no example of the remove syntax. The in-session /skills remove <directory> is documented and only works for skills you added directly, not ones that came with a plugin.
Personal skills in ~/.copilot/skills are on your machine. They are not available to the Copilot cloud agent running on github.com unless you also put them in .copilot/skills in your dotfiles repo, and even that doesn’t apply to Actions-based sessions. If a skill matters to the team, commit it to the repo.
The matching is good but not deterministic. “Check the tags” triggered my skill every time I tried it today. A vaguer prompt might not. When it has to run, use the slash form.
There are no documented size limits for SKILL.md or the folder. That doesn’t mean there aren’t any, so keep the file to the instructions and push the bulk into reference documents the model reads on demand.
And the usual one: all of this is from CLI 1.0.105 in November 2026. The CLI changes often. copilot skill --help is quicker than searching when a flag has moved.
Final thoughts#
Go and look at your custom agents and your copilot-instructions.md, and find the biggest block of text in there that only matters for one kind of task. Mine was a tagging standard. Yours might be a naming convention or the list of KQL mistakes you keep correcting in other people’s alert queries. Cut it out, put it in .github/skills/<name>/SKILL.md with a description that says when to use it, and put the detail in a second file next to it. Run copilot skill list, then ask Copilot to do the thing without naming the skill and see if it picks it up. Commit the folder. Everyone who clones the repo gets it, and so does anyone using Claude Code or Codex on the same code.



