Skills API
Manage skills in the Skill Library. Skills are reusable knowledge packages (markdown instructions) that teach agents how to handle specific tasks.
Skills are separate from Prompts -- prompts are templates for LLM messages, while skills are behavioral instructions for agents.
Authentication
All endpoints require a valid API key via the X-API-Key header:
X-API-Key: sk-prod-...
Skill Object
| Field | Type | Description |
|---|---|---|
_id | string | Unique skill ID |
name | string | Skill name |
description | string | What the skill does and when to use it |
content | string | The skill's instructions (markdown). The SKILL.md a model reads is this body under a frontmatter built from name and description |
variables | array | Template variables extracted from {{name}} syntax |
tags | array | Tags for categorization and discovery |
linkedIds | array | Agent IDs the skill belongs to |
category | string | Skill category (e.g., "tools", "agent", "support") |
currentVersion | number | Current version number |
ownerId | string | Owner user ID |
ownerName | string | Owner display name |
sharedWith | array | User IDs with read access |
isPublic | boolean | Whether the skill is publicly visible |
source | string | Origin: user, marketplace, github:owner/repo |
mcpTools | array | MCP tool names this skill references |
githubUrl | string | GitHub source URL (if imported) |
usageCount | number | How many times the skill has been used |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last update timestamp |
Version Object
| Field | Type | Description |
|---|---|---|
_id | string | Version ID |
skillId | string | Parent skill ID |
versionNumber | number | Sequential version number |
parentVersionNumber | number | The version this one follows (0 for version 1) |
contentPatch | string | Unified diff from the previous version's content to this version's (version 1 is a diff from empty text) |
sideFields | object | { variables }: the variables at this version |
changeNote | string | Description of what changed |
createdAt | string | ISO 8601 timestamp |
createdBy | string | User ID who created this version |
createdByName | string | Display name |
Endpoints
List Skills
GET /api/v1/library/skills
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
q | string | Search by name or description |
tags | string | Comma-separated tags to filter by |
category | string | Filter by category |
limit | number | Max results per page (default: 20, max: 100) |
cursor | string | meta.nextCursor of the previous page; omit for the first page |
Response:
{
"data": [
{
"_id": "abc123",
"name": "Product Search",
"description": "Semantic search across product catalog",
"tags": ["search", "milvus"],
"category": "tools",
"currentVersion": 3,
"ownerName": "Admin",
"isPublic": false,
"source": "marketplace",
"usageCount": 42,
"updatedAt": "2026-03-27T00:00:00.000Z"
}
],
"meta": {
"total": 15,
"limit": 20,
"nextCursor": null,
"requestId": "req_abc123"
}
}
Create Skill
POST /api/v1/library/skills
Request Body:
{
"name": "Product Search",
"description": "Semantic search across the product catalog",
"content": "# Product Search\n\n## When to Use\nUser asks to find products...\n\n## Instructions\n...",
"tags": ["search", "milvus"],
"category": "tools",
"mcpTools": ["product_search"]
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Skill name, kebab-case: lowercase letters, digits and hyphens, starting with a letter, up to 64 characters (product-search). Agents find a skill by its name; any other name is refused with 400 |
content | string | Yes | The instructions in markdown (supports {{variables}}). A whole SKILL.md is accepted: its frontmatter is dropped (the frontmatter description is used when you send no description), so the stored content is the body |
description | string | No | Description |
tags | array | No | Tags for discovery |
category | string | No | Category |
mcpTools | array | No | MCP tool names this skill uses |
source | string | No | Source identifier (default: "user") |
Response: 201 Created
{
"data": { "skillId": "abc123", "action": "created" },
"meta": { "requestId": "req_abc123" }
}
action is created for a new skill. When you already have an identical skill, the response is 200 OK with action: "unchanged"; when you have a skill of the same name with different content, that skill gets a new version and the response is 200 OK with action: "superseded".
Get Skill
GET /api/v1/library/skills/:id
Returns the full skill with content (excluding embedding vector).
Response:
{
"data": {
"_id": "abc123",
"name": "Product Search",
"content": "# Product Search\n\n## When to Use\n...",
"variables": [
{ "name": "limit", "required": true }
],
"tags": ["search"],
"category": "tools",
"currentVersion": 3,
"mcpTools": ["product_search"]
},
"meta": { "requestId": "req_abc123" }
}
Update Skill
PATCH /api/v1/library/skills/:id
Content changes automatically create a new version. A new name must be kebab-case, as on create; a skill named before that rule keeps its name until it is renamed.
Request Body:
{
"content": "# Updated Product Search\n\n...",
"changeNote": "Added error handling instructions"
}
Delete Skill
DELETE /api/v1/library/skills/:id
Deletes the skill and all its versions. Cannot be undone.
List Versions
GET /api/v1/library/skills/:id/versions
Returns all versions, newest first, each with content: the skill's instructions at that version (rebuilt from the diff chain).
Restore Version
POST /api/v1/library/skills/:skillId/versions/:version/restore
Creates a new version with the content of version :version.
Duplicate Skill
POST /api/v1/library/skills/:id/duplicate
Creates a copy owned by the current user, named with a -copy suffix (product-search becomes product-search-copy, still kebab-case).
Render Skill
POST /api/v1/library/skills/:id/render
Renders the skill content with variable substitution.
Request Body:
{
"variables": {
"limit": "10",
"category": "Handguns"
}
}
Response:
{
"data": {
"content": "Rendered content with variables replaced...",
"skillId": "abc123",
"name": "Product Search"
},
"meta": { "requestId": "req_abc123" }
}
Record Usage
POST /api/v1/library/skills/:id/usage-events
Record that the skill was used. Answers 201 Created with { "usageCount": 3 }, how many times it has been used.
Assess Skill
POST /api/v1/library/skills/:id/assess
Runs the quality ruleset over the skill's current content and returns a score plus recommendations. Modeled after Anthropic's skill-building guide -- checks structure, presence of "When to Use", instruction clarity, variable usage, etc.
Path Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Skill ID |
Request Body: None.
Response:
{
"data": {
"score": 50,
"caps": [
{ "limit": 50, "reason": "A critical check fails: Name is kebab-case." }
],
"grade": "D",
"checks": [
{
"id": "body.has-instructions-section",
"category": "instructions",
"severity": "high",
"title": "Has actionable instructions",
"status": "pass",
"passed": true,
"weight": 4,
"awarded": 4,
"message": "Actionable structure present."
},
{
"id": "body.actionable-language",
"category": "instructions",
"severity": "high",
"title": "Avoids vague instruction phrases",
"status": "warn",
"passed": false,
"weight": 3,
"awarded": 0.6,
"message": "Vague phrasing found in 2 line(s).",
"recommendation": "Replace \"make sure to…\", \"as appropriate\" with explicit commands and concrete checks."
},
{
"id": "cohesion.description-promises-met",
"category": "instructions",
"severity": "high",
"title": "Body delivers on the description's promises",
"status": "skipped",
"passed": false,
"weight": 4,
"awarded": 0,
"message": "Body too short to evaluate cohesion."
}
],
"recommendations": [
{
"id": "body.actionable-language",
"category": "instructions",
"severity": "high",
"title": "Avoids vague instruction phrases",
"status": "warn",
"passed": false,
"weight": 3,
"awarded": 0.6,
"message": "Vague phrasing found in 2 line(s).",
"recommendation": "Replace \"make sure to…\", \"as appropriate\" with explicit commands and concrete checks."
}
],
"categoryScores": {
"instructions": { "weight": 7, "awarded": 4.6, "score": 66 }
},
"rulesetVersion": "1.0.0",
"assessedAt": "2026-03-27T00:00:00.000Z"
},
"meta": { "requestId": "req_abc123" }
}
| Field | Description |
|---|---|
score | 0 to 100: the weighted category totals, held to any caps |
caps | Each ceiling that lowered the score, with its reason: missing frontmatter, name or description (8, 15 or 30), instructions under 100 characters (45), a critical check failing (50), two or more failing checks (60), or 7, 11 or 16 warning checks (88, 82, 72). Empty when the score is the category total |
checks[].status | pass, warn, fail, or skipped when the check was not evaluated for this skill (for example a cohesion check on a body too short to judge). A skipped check earns nothing and counts toward nothing |
checks[].awarded | Points earned out of weight: all on a pass; on a warn 10% (critical), 20% (high) or 45% (medium) of it; none on a fail or a skip |
recommendations | The checks that warn or fail, most severe first |
categoryScores | Per category, over its evaluated checks; score is null when none was evaluated |
recommendations holds the checks that did not pass, most severe first. categoryScores has one entry for each of naming, description, instructions, progressive-disclosure, discoverability, structure and safety (one shown).
Required Scope: skills:read
Import from GitHub
POST /api/v1/library/skills/import
Imports a skill folder from GitHub: its SKILL.md and every text file under the folder (references/, scripts/, assets/ and any other) as supporting files. githubUrl is the repository (the skill at its root), a folder in it (/tree/<branch>/<path>) or a file in the folder; a URL without a branch reads the repository's default branch. The skill is named by the name in its frontmatter, else the folder's name, which must be kebab-case. A folder without SKILL.md is refused (github-no_skillmd).
Request Body:
{
"githubUrl": "https://github.com/anthropics/skills/tree/main/skills/brand-guidelines"
}
Response: 201 Created
{
"data": {
"skillId": "abc123",
"action": "created",
"name": "brand-guidelines",
"description": "Applies Anthropic's official brand colors and typography...",
"filesCount": 1,
"skippedFiles": []
}
}
action is unchanged when the same skill is already in the Library. skippedFiles lists binary files (images, fonts), which are not imported: a skill's files are text.
List a Skill's Files
GET /api/v1/library/skills/:id/files
The files bundled with a skill: { skillId, count, files }, each file its path and size (no
contents). A skill's instructions say which files matter and when; read only those.
Scope: skills:read
Read a Skill File
GET /api/v1/library/skills/:id/contents?path=templates/report.md
One bundled file: { skillId, path, content }. path=SKILL.md gives the skill's SKILL.md, its
frontmatter composed from its name and description.
Scope: skills:read
Search Skills
POST /api/v1/library/skills/search
The skills relevant to a turn, ranked by meaning and keywords, and the markdown block an agent puts in its system prompt.
Scope: skills:read
| Field | Type | Required | Description |
|---|---|---|---|
userTurn | string | No | The current turn |
limit | integer | No | How many (default 5, at most 50) |
tags | string[] | No | Only skills with all of these tags |
Response 200 OK: { skills, count, contextBlock }.
Python SDK
from strongly import Strongly
client = Strongly(api_key="sk-prod-...")
# List skills
for skill in client.skills.list(category="tools"):
print(f"{skill.name} (v{skill.current_version})")
# Create a skill
result = client.skills.create(
name="My Skill",
content="# My Skill\n\nInstructions...",
tags=["custom"],
)
skill_id = result.id
# Get skill content
skill = client.skills.retrieve(skill_id)
print(skill.content)
# Update with versioning
client.skills.update(
skill_id,
content="# Updated content",
change_note="Improved instructions",
)
# Render with variables
rendered = client.skills.render(skill_id, {"limit": "10"})
print(rendered.content)
# Import from GitHub
client.skills.import_from_github("https://github.com/owner/my-skill")
# List versions
versions = client.skills.list_versions(skill_id)
for v in versions:
print(f"v{v.version_number}: {v.change_note}")
Scopes
| Scope | Endpoints |
|---|---|
skills:read | GET /library/skills, GET /library/skills/:id, GET /library/skills/:id/versions, POST /library/skills/:id/render, POST /library/skills/:id/usage-events, POST /library/skills/:id/assess |
skills:write | POST /library/skills, PATCH /library/skills/:id, DELETE /library/skills/:id, POST /library/skills/:skillId/versions/:version/restore, POST /library/skills/:id/duplicate, POST /library/skills/import |