Upload a skill
Creates a workspace-owned skill from caller-supplied content. The body may be either inline markdown (wrapped automatically as SKILL.md) or a multi-file pack of base64-encoded files that must include a SKILL.md at the root. The display name must be 3 to 60 characters of letters, digits, spaces, hyphens, or underscores and is used to derive the slug; an optional runtime profile (claude-sdk, hermes, or openai-agents; defaults to claude-sdk) and an optional capability slot may be set. Size limits apply (up to 50 files, 256 KiB total raw content, 64 KiB markdown, and a 1 MB request limit). Re-uploading with the same derived slug updates the existing skill in place. Returns the resulting slug and version with HTTP 201. Admin only; scoped to the caller’s own workspace.
Authorizations
Personal Access Token. Send as Authorization: Bearer hq_pat_....
Body
Base64-encoded payload. 16 MiB cap on the JSON body limits raw to ~12 MiB - the multipart streaming path lands in pass 2.
Free-form user category; the auto-categoriser may overwrite this in a follow-up worker pass once we have Haiku wired.
Required iff scope == "channel".
private | channel | team. Defaults to private.
Response
Workspace skill created
True iff this hashed identical to an existing document in this tenant - we still record the new metadata row but the Trove object is shared. The UI surfaces this as a "saved (dedup'd against existing copy)" hint.
x >= 0True iff this was a same-owner/same-scope dedup AND the caller supplied new metadata (tags/caption/category) that we actually merged onto the existing row. Lets the UI say "already in your library - details updated" honestly vs a bare "already there".