Why your Copilot CLI skill isn't being used
A skill is a folder of instructions that GitHub Copilot CLI loads only when a task calls for it. Each skill lives in its own directory with a SKILL.md file: a frontmatter block at the top (metadata between --- lines) with a name and a description, then the instructions themselves. A skill is different from AGENTS.md, which is added to every session. A skill is meant to be chosen, either by you with /skill-name or by the model when your prompt matches the description.
Most reports are not about a missing file. The skill shows up in /skills list and then nothing happens, or it is named in a prompt and the CLI answers "Skill not found". Those are different failures with different checks.
Run copilot --version before changing anything. The changelog moves weekly: 1.0.104 on 27 October 2026.
Checked against GitHub's Copilot CLI documentation on 27 October 2026.
Status, 27 October 2026: several open reports sit behind the same symptom. disable-model-invocation makes a skill unreachable through the model-facing tool, even when named, while the interactive slash command can still load it (#4438, open, updated 19 October 2026). Plugin skills can be listed but left out of the model's skill list (#2753, open; #4886, open). Large skill libraries are truncated in the injected list (#1464, open; #2314, open). The checks below work either way.
Three failures that look alike#
| What you see | What it usually means | First check |
|---|---|---|
The skill is not in /skills list at all | Discovery: wrong directory, wrong file name, invalid frontmatter, or a source the CLI does not read | copilot skill list --json |
| It is listed, but the model never picks it | Selection: the description does not match the task, or the skill fell outside the injected list | /skills info NAME, then the prompt in a debug log |
| You name it and get "Skill not found" | Invocation: a frontmatter flag, a stale registry, or the known tool-path bug | The transcript line for the skill call |
Do not treat "the model says it loaded the skill" as evidence: it can read the file with ordinary tools and report success without the skill ever being invoked. A real invocation appears in the transcript as a skill(...) tool call, and a failure appears as Skill not found. That line is the evidence.
Prove what Copilot discovered#
Outside a session, list every source the CLI can see:
copilot skill list --jsonEach row has a name, description, source, path, and enabled flag. The path is the useful part: it tells you whether Copilot found the copy in your repository, in your home directory, in a plugin, or in a registered directory. Inside a session, /skills list shows the interactive view, and /skills info NAME shows one skill's details and location. Use /env when you need the loaded set as a whole: instructions, MCP servers (external tool servers), skills, agents, hooks, plugins, LSPs, and extensions.
If copilot skill list --json shows the skill but /skills list does not, two registries disagree. That is a reported problem for plugin skills, and in some cases the skill stops working after startup even though /plugin list still shows the plugin (#4886, open). Restart before you edit the skill.
Where Copilot CLI looks for skills#
The CLI reference lists these locations in priority order. For duplicate names, the first local source wins. Two plugins with the same skill name both stay available under qualified names; the bare name routes to the higher-priority plugin.
| Location | Scope |
|---|---|
.github/skills/ | Project |
.agents/skills/ | Project |
.claude/skills/ | Project, Claude-compatible |
Parent .github/skills/ | Inherited, for monorepos |
~/.copilot/skills/ | Personal |
~/.agents/skills/ | Personal, shared across agents |
| Plugin directories | Installed plugins |
COPILOT_SKILLS_DIRS | Custom directories |
.github/skills/ under a directory added with --add-dir | Added root |
| Org/enterprise | Remote, fetched on demand; same name priority |
| Built-in skills | Shipped with the CLI |
A project skill wins over a personal skill with the same name (configuration reference). The file name is exact: SKILL.md, not SKILL.md.md or skill.md. Use a lowercase, hyphenated directory name. The frontmatter needs name and description; the description limit is 1,024 characters. Malformed YAML will not load, and version 1.0.69 added loading errors to copilot skill list, so read those warnings first.
Four traps account for most discovery failures:
- You came from Claude Code and kept the personal copy in
~/.claude/skills. Project.claude/skillsstill works, but user-level Claude skills stopped loading in 1.0.36 (changelog). Use~/.copilot/skillsor~/.agents/skills. - You set
COPILOT_HOME. WithCOPILOT_HOMEor--config-dir, the CLI stops loading~/.agents/skills(changelog 1.0.66). Put personal skills in$COPILOT_HOME/skills. - You added the directory with
--add-dir. Only.github/skillsunder the added directory is loaded. An older report says nothing loaded at all (#3173, open, filed on 1.0.43); a later changelog entry fixes a load race. Check your version. - The personal directory is not being enumerated. On 1.0.81-5, a report says
~/.copilot/skillswas never discovered, while the same skill worked when registered as a custom directory (#4545, open).copilot skill add <path>is the workaround, not a fix.
Listed but never chosen: the description is the trigger#
Normally, before a skill is invoked, the model has only the name and the description, not the body. The skills documentation says Copilot decides when to use a skill "based on your prompt and the skill's description", and injects SKILL.md only after it chooses.
The description is therefore a routing rule, not a summary. Say what the skill does and which situations should call it, in the words a person would use for the task.
Too vague:
description: Helps with tests.Better:
description: Writes and repairs Jest tests for this repository. Use when adding tests, fixing a failing test, or raising coverage in packages/api.Name the task, the verbs, and the part of the repository.
If the skill still loses to the model's own approach, name it: "Use the /frontend-design skill to build the navigation bar." In the interactive CLI you can also type it as a command, /frontend-design build the navigation bar, which resolves the skill before the model starts.
Those two paths are not identical. The slash command injects the skill directly; a sentence containing /frontend-design goes through the model-facing skill tool. Usually both work. The next section is the case where only the slash command does.
The injected list has a budget#
Copilot CLI puts a compact list of available skills into the system prompt (the instructions the CLI sends before your message). In reports from early builds (0.0.409 and 0.0.412), that list was capped. When a library is large, the prompt contains a comment such as:
<!-- Showing 32 of 63 skills due to token limits -->One report with 201 installed skills saw Showing 25 of 201 skills (#2314, open). Another reproduced the cut at roughly the 32nd skill in alphabetical order and found that a later skill was never selected until the library was reduced to 32 (#1464, open).
No documented command prints the injected list, so the direct check is the prompt in a session log. Start with --log-level debug (or all), then read the process-*.log file; /session prints the log path for the current session.
The skills after the cut are absent from the model's list, so it cannot choose them on its own. The changelog says skills beyond the token limit have stayed discoverable and invocable by name since 1.0.32, so explicit naming is the fallback; an early report of the tool failing for a truncated skill predates that change. The headless (non-interactive) -p path also has a separate open report of intermittent "No model-invocable skills available" (#4838, open; maintainer asked for a retest on 1.0.103 on 26 October 2026).
Reduce the list instead of hoping for a bigger budget:
- Disable skills you do not use:
copilot skill disable NAME, or open/skillsand toggle them. - Exclude whole directories with
ignoredSkillsLocationsinsettings.json. - Keep personal skills to the handful you use across repositories; keep project-specific skills in the project.
- Shorten the longest descriptions. The budget is consumed by the rendered list; one report in #1464 shortened 32 descriptions and fit more of them in.
- If a skill must apply to every task, put the rule in
AGENTS.mdorcopilot-instructions.md, where it is loaded without being chosen.
It is listed, you named it, and it still fails#
Check the frontmatter first. disable-model-invocation: true is documented as preventing automatic invocation, while user-invocable defaults to true and controls whether /SKILL-NAME exists (frontmatter reference). The intent is manual-only, not unreachable.
Current builds do not reliably honour that intent. The open report shows the interactive slash command injecting the flagged skill, then the assistant calling the skill tool, which resolves against the filtered list and returns Skill not found. A comment there says a leading slash in prompt mode (copilot -p) is passed through as plain text, so a flagged skill can be unreachable there. The changelog entry for 1.0.74 reads "Fully honor the skill disable-model-invocation flag," but reproductions continue through 1.0.87 and the desktop app; a related report was closed as a duplicate on 26 October 2026.
If you need the skill to work today, remove disable-model-invocation: true when automatic selection is acceptable; that is the report's control case. If it must stay manual, use the interactive /skill-name command and expect that the assistant may make a redundant failing tool call. For copilot -p or another headless run, use an unflagged copy or move the instructions into the prompt.
Also check user-invocable: false: it removes the slash command, so a manual-only skill with this flag has no supported way to run.
If the skill was added during the session, /skills reload should pick it up. An open report says reload counts the new skill but /skills list omits it until the process restarts (#3643, open, filed on 1.0.59). Restart first.
Make the skill worth invoking#
Keep the body procedural: the steps, the commands, the files to read, and the output you expect. If the skill runs scripts, reference them by path from the skill's directory; Copilot discovers the files next to SKILL.md when the skill is invoked.
allowed-tools can pre-approve tools while the skill is active. Only list shell or bash if you have read the skill and its scripts and trust them: the documentation warns that pre-approving the shell removes the confirmation step for arbitrary commands. For a skill you did not write, leave it out.
A skill is not a permission rule. If the requirement is "never push to main" or "always run the tests before committing", enforce it with permissions or a hook and keep the prose in the instruction file. A skill is for a task that should load when relevant.
Where to go next#
- Copilot CLI guides — the rest of the set: instructions, sessions, agents, permissions, and hooks.
- Why Copilot CLI ignores your AGENTS.md or instructions — when the rule that should always apply is not loading at all.
- Custom agents in Copilot CLI — when the skill belongs to an agent, and the agent is the thing that is not loading.