Skills
Private skill versions, listing, and progressive load.
Workspace skills under /api/v1/skills. CRUD accepts any valid bearer key. POST /api/v1/skills/load requires a workspace-scoped key. Missing token → 401 { "error": "Valid bearer API key is required" }. Load with personal/copilot → 403 { "error": "A workspace API key is required." }.
No cursor pagination. CRUD has no Idempotency-Key. Publication (request/publish/rollback) is session-only (/api/skills/{id}/publication), not v1.
Endpoints
| Method | Path | Envelope |
|---|---|---|
| GET | /api/v1/skills | { skills[] } |
| POST | /api/v1/skills | 201 { skill } |
| GET | /api/v1/skills/{id} | { skill } |
| PATCH | /api/v1/skills/{id} | { skill } |
| DELETE | /api/v1/skills/{id} | { deleted: true } |
| POST | /api/v1/skills/load | Progressive load (see below) |
Missing / undiscoverable id → 404 { "error": "Skill not found." }.
Skill object (CRUD)
id, workspaceId, optional ownerId, name, description, instructions, enabled, visibility (private | workspace), publicationStatus (draft | pending | published | archived), version, optional parentVersionId / reviewer / publication timestamps, usageCount, createdAt, updatedAt, optional lastUsedAt.
Discoverability: published workspace skills are visible to the workspace. Private draft/pending skills are visible only to the API key userId (the owner). Archived / unpublished rows are omitted from v1 list (includePendingReview is not exposed).
List and create
GET ?query= substring match (case-insensitive) on name, description, or instructions.
POST JSON:
| Field | Notes |
|---|---|
name + instructions | Required unless importing content |
description | Optional |
enabled | Default true |
content | Skill markdown. Frontmatter name/description and body instructions; name may come from first # heading (slugified) |
Import errors → 400 ("Skill content is required.", "Skill name is required in frontmatter or first heading.", "Skill instructions are required."). Missing name/instructions → 400 { "error": "Skill name and instructions are required." }. Owner is apiKey.userId; empty owner → "A private skill owner is required.".
Creates a private draft. Same owner + case-insensitive name with an active private draft updates that draft and still returns 201. Active pending review for that name → 400 "This skill already has a version awaiting publication review.". Otherwise a new version is created (parentVersionId of the prior lineage).
Update and delete
Only the owner (canEditWorkspaceSkill). Else 400 { "error": "Only the skill owner can edit this skill." } (or delete equivalent). PATCH fields: enabled, description, instructions (not name).
Private draft updates in place. Other statuses: pending private may be archived, then a new private draft version is created and returned.
Delete: published workspace skills → 400 "Published skills cannot be deleted. Roll back or archive the publication first."
Progressive load
POST /api/v1/skills/load — Cache-Control: private, no-store. Strict JSON:
| Field | Notes |
|---|---|
skillIds | Up to 32 non-empty ids (max length 191); duplicates skipped |
skillId | Legacy single id |
skillName | Used only when no id selectors remain |
versions | Map id → positive int |
version | Legacy version for skillId / skillName |
At least one of skillIds, skillId, skillName. Extra keys or invalid shape → 400 { "error": "Invalid progressive skill load request." } (no code).
Success 200:
{
"capability": "skills.load",
"effect": "read-only",
"skills": [{ "id": "", "workspaceId": "", "name": "", "description": "", "instructions": "", "version": 1, "files": [] }],
"compatibility": { "usedLegacyFields": false }
}
files[]: id, name, mimeType, sizeBytes, sha256, status: "ready".
| Status | Body |
|---|---|
| 400 | { error, code: "PROGRESSIVE_SKILL_INVALID_REQUEST" } (service-level) |
| 409 | { error, code: "PROGRESSIVE_SKILL_VERSION_MISMATCH" } |
| 404 | { "error": "Skill not found.", "code": "PROGRESSIVE_SKILL_NOT_AVAILABLE" } (missing, unauthorized, or unread file — indistinguishable) |
| 500 | { error } |
The handler enabled() is currently always true (404 "Progressive Skills is not enabled." is not reachable).
Known gaps
- No v1 publication/review endpoints.
- PATCH cannot rename.
- List does not expose pending-review-for-admins (
includePendingReview). - Load returns full
instructions(CRUD list also returns them). Runtime summaries elsewhere omit instructions; this route does not.
