Skills through the API¶
The concept behind agents is explained in Agents.
On this page you upload a skill through the API and offer it on a turn. A skill packages reusable instructions for a task, such as writing release notes or triaging tickets. You store the package once and offer it on the turns that need it. When the model has to execute an action, use tools.
Your key needs the skills capability. You do the same with a mouse in
Skills in the console.
Package format¶
Core supports the Agent Skills
format. A package
contains SKILL.md and optional supporting text files. In SKILL.md, place name and
description in a metadata block between --- lines, followed by Markdown instructions.
---
name: release-notes
description: Write release notes for one version from a list of merged changes.
---
Group the changes under Added, Changed, Fixed. One line each, in the past tense, naming
what a reader can now do. Never mention an internal ticket id.
See `examples.md` for two notes written this way.
Upload a skill¶
curl -s -X POST "$CORE_URL/skills" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d @- <<'JSON'
{
"skill_md": "---\nname: release-notes\ndescription: Write release notes...\n---\n\nGroup the changes...",
"resources": [{ "path": "examples.md", "content": "## 2.4.0\n\n### Added\n..." }]
}
JSON
| Call | Answers |
|---|---|
POST /skills |
201 + Location; 409 if the name is taken |
GET /skills |
your skills, cursor-paged |
GET /skills/{skill_id} |
one skill: name, description, body, and each resource's path and size |
GET /skills/{skill_id}/resources/{path} |
one resource's content |
PUT /skills/{skill_id} |
replace body, description and resources |
DELETE /skills/{skill_id} |
204 |
Listings include resource paths and sizes. Fetch a resource separately when you need its content.
A resource path is relative and may contain / to place files in folders, such as
templates/summary.md; fetch it with the path as is: GET /skills/{skill_id}/resources/templates/summary.md.
A path uses letters, digits, ., _, - and /, up to 200 characters; it must not start with
/ or contain a .. segment, and each path in a skill is unique. Write each path in its plain
form, without //, ./ or a trailing /: the API normalises the URL it is fetched by, so a
resource stored under such a path cannot be fetched by it.
DELETE answers 409 while the latest version of an agent links the skill by its id or its name;
the error lists the agents in conflicts, at most the first twenty, and counts the ones your key
may not read in withheld (the fields). An agent is also refused, with a 422 on the
entry, when it names a skill your organisation does not have.
PUT requires the existing package name; changing it returns 409. To rename a skill, create a new
one, update references and delete the old one when it is no longer used.
Every PUT writes the skill's next version. An administrator can also save one as a draft, in
the console or its API: your key does not see a draft. GET answers
the published version, a skill that has only a draft does not exist for your key, and a reference
release-notes@3 to a draft number answers 404 as for a version never written. The draft takes
effect when it is published.
Unknown metadata fields, missing name or description, absolute resource paths and paths
containing .. return 422 with the affected field.
Offer a skill¶
{
"model": "<a model id>",
"skills": ["release-notes"],
"input": "Write the notes for 2.4.0 from these merged changes: ..."
}
Pass up to 32 skill names or skill_ ids in skills. An unavailable reference or disabled
capability returns 404. Check GET /key and the skill identifier when troubleshooting.
Your key's policy decides which skills it reaches. A skill the policy does not name is absent from
GET /skills, answers 404 by id, and is never offered or injected on a turn, retrieval-driven
loading included. Storing a package under a name the policy does not
name answers 403.
Skill loading¶
The key configuration selects one of two loading methods:
- Model-driven (the default) — Core offers a
builtin__load_skilltool listing only the skills this request named, with each one's description. The model reads a skill when it decides it needs one, and can ask for a packaged resource by path. Linking skills is what offers it: a request that names it intools[]answers400. - Retrieval-driven — Core compares your turn's own last user text against each named skill's
description and injects the best matches directly, before the model runs: those scoring at
least
min_score, at mostretrieval_top_kof them. A matching skill is never left out for the length of its body; the turn's trace shows how many were left out by the count and what the injected bodies cost. Nobuiltin__load_skilltool is offered; the choice was already made.
In both modes, the skill body is a trusted instruction at the same authority level as
instructions. Only store instructions you intend to grant that authority.
Audit records¶
The audit history records writes (skill.created, skill.replaced,
skill.deleted) and use (skill.loaded, skill.injected) with the originating request id. Use
these events to check which instructions a turn loaded.