Install reusable procedures the agent can draw on, and manage which ones are active.
A skill is a reusable procedure you install into a project. It is a Markdown file — instructions the agent reads and follows when the task calls for it. "How we format the monthly revenue report", "how to reconcile the two order tables", "which caveats to attach to churn numbers."
Where Memory is what the agent learns about one user, a skill is what your team has decided is the right way to do something.
How a skill is put together
Every skill is a directory whose entry point is SKILL.md: YAML frontmatter naming it, then a Markdown body.
---
name: revenue-report
description: Formats the monthly revenue report the finance team expects.
---
When asked for the monthly revenue report:
1. Pull net revenue by product line for the requested month.
2. Compare against the same month last year.
3. Present as a table, figures in millions, two decimal places.
4. Call out any line that moved more than 15% year over year.description is what the agent matches against when deciding whether a skill applies, so write it as a trigger, not a summary.
A skill can be more than one file — supporting templates or reference data live alongside SKILL.md in the same directory.
Built-in versus project skills
| Built-in | Project | |
|---|---|---|
| Where from | Packaged with Wren | Installed by you |
| Deletable | No | Yes |
| Downloadable | No | Yes |
| Overridable | Install a project skill of the same name and it shadows the built-in | — |
Listing returns both, merged, with isBuiltin telling them apart. Deleting a project skill that shadowed a built-in makes the built-in visible again.
Endpoints Overview
| Endpoint | What it does |
|---|---|
GET /v2/projects/{projectId}/skills | List the project's skills merged with the built-ins. |
POST /v2/projects/{projectId}/skills | Create a skill from a zip or a JSON body. |
GET /v2/projects/{projectId}/skills/{skillName} | Read one skill's body and file manifest. |
DELETE /v2/projects/{projectId}/skills/{skillName} | Delete a project skill. |
GET /v2/projects/{projectId}/skills/{skillName}/download | Download a skill as a zip. |
PUT /v2/projects/{projectId}/skills/{skillName}/disabled | Enable or disable without deleting. |
Basic Usage
Create a single-file skill
The simplest case — no zip, just the frontmatter fields and the body:
{
"name": "revenue-report",
"description": "Formats the monthly revenue report the finance team expects.",
"content": "When asked for the monthly revenue report:\n\n1. Pull net revenue by product line for the requested month.\n2. Compare against the same month last year.\n3. Present as a table, figures in millions."
}{
"name": "revenue-report",
"fileCount": 1
}The SKILL.md is assembled server-side. name is lowercase kebab-case and also becomes the directory name.
Create a multi-file skill
Send multipart/form-data with a .zip containing exactly one top-level directory, which must contain SKILL.md:
revenue-report/
├── SKILL.md
└── templates/
└── summary-table.md
| Limit | Value |
|---|---|
| Compressed | 5 MB |
| Uncompressed | 20 MB |
| Files | 100 |
This is the same layout download returns, so a skill round-trips: download it, edit it, upload it again.
List what a project has
{
"skills": [
{
"projectId": 1,
"name": "revenue-report",
"description": "Formats the monthly revenue report the finance team expects.",
"isBuiltin": false,
"isDisabled": false,
"lastModified": "2026-08-02T09:20:11.000Z"
},
{
"projectId": 1,
"name": "data-quality-check",
"description": "Checks a table for nulls, duplicates and stale partitions.",
"isBuiltin": true,
"isDisabled": false,
"lastModified": "2026-07-18T00:00:00.000Z"
}
]
}Turn one off without deleting it
{
"disabled": true
}{
"name": "revenue-report",
"disabled": true
}A disabled skill stays in the project but is withheld from the agent. It takes effect for the next turn — a turn already running keeps the skills it started with.
Editing a skill
There is no update endpoint. Download, edit, delete, re-create:
// 1. Download the current version as a zip.
const zip = await getBinary(`/v2/projects/1/skills/revenue-report/download`);
// 2. Edit SKILL.md locally, rezip.
// 3. The name is taken, so remove the old one first — 409 otherwise.
await del(`/v2/projects/1/skills/revenue-report`);
// 4. Upload the edited zip.
await postMultipart(`/v2/projects/1/skills`, { file: editedZip });Re-using an existing skill name returns 409. Built-in skills cannot be overwritten, deleted, or downloaded.
Frontmatter is validated on create, exactly as in the UI upload path — a missing
nameordescriptionis rejected with400. No execution check is performed, so a skill that parses but gives bad instructions installs fine. Test it with a turn.
