A skill is a named instruction packet with a description of when it applies — your house style, your editorial rules, the shape you want a product description to take.
Two sources, one catalogue
| Source | Scope | Who |
|---|---|---|
| Declared in code, on the plugin | Every workspace | An operator, at deploy time |
| Authored in the admin | One workspace | An admin, at runtime |
CopilotPlugin({
skills: [
{
name: 'house-style',
description: 'How we write headlines and standfirsts.',
instructions: '…',
always: true
}
],
providers,
config
});Code-declared skills are validated at construction, like the provider list.
The two are merged, and code wins a name collision. The admin write routes refuse a colliding name up front, so reaching that merge means a deploy took a name over rather than a request doing so.
Three ways a skill reaches a run
All three are the system prompt.
| Channel | Effect |
|---|---|
always | In force for every run in its workspace. |
| Attached in the composer | In force for that turn. |
| Everything else enabled | Appears as name — description only. |
That third channel is the interesting one. Every other enabled skill is advertised by name and description only, so the model can recommend a skill it was not given — “this looks like a product description; want me to use the product-copy skill?” — without its instructions costing context on every run.
Skill bodies are injected after the security rules a skill must not override, and before the style rules it should refine.
No tool delivers a skill
Progressive disclosure through a copilot_skill_read tool is the obvious design,
and it is rejected.
It would mean either carving an exception into the untrusted-content fence for one tool name, or handing the model instructions labelled as inert data and relying on it to disobey the label. Neither is a good trade for saving some prompt tokens.
Skills arrive through the system prompt or they do not arrive.
Managing skills
| Route | Does |
|---|---|
GET /api/copilot/skills | The skills available in this workspace |
GET /api/copilot/skills/manage | Every skill, for the management page |
GET /api/copilot/skills/:id | One skill, including its instructions |
POST /api/copilot/skills | Create one in this workspace |
PATCH /api/copilot/skills/:id | Edit one |
DELETE /api/copilot/skills/:id | Delete one |
A code-declared skill is not editable through these routes — it is part of the deployment.
Skills are instructions, not capabilities
A skill cannot add a tool, widen a permission, or reach data the caller could not. It is text in a system prompt. A skill that says “you may publish” changes nothing: there is no publish tool, and the permission check does not read the prompt.