list_skills
Read-only
List the workspace’s SKILLS: short markdown documents the workspace’s own members wrote for agents — how they diagnose a metric, their house chart conventions, which sources they trust, the recipe for a recurring report. Each row carries id (the handle — the only way to name a skill back to a tool), name (a display label that MAY repeat: two skills can legitimately share one), a one-line description of WHEN to use it, updatedAt/updatedBy, and archived. Call this EARLY: when a request sounds like a standing procedure (“the monthly board deck”, “why did revenue drop”), when the user names a skill, or before planning multi-step work in a workspace you don’t know — a skill encodes what this workspace knows about its own data, which you cannot infer from the dashboards. Descriptions only; read the instructions themselves with get_skill. Each row also carries ownerId + ownerName; pass ownerId (a uid from list_workspace_members, or from a member the user attached) to list only that person’s skills. Archived skills are hidden unless includeArchived:true. Lists the skills YOU may open (per-skill grants + workspace default). To find a skill BY NAME OR KEYWORD, call search_skills instead of listing everything and filtering the names yourself — it matches names and descriptions and ranks the hits.
search_skills
Read-only
Find a workspace SKILL by name or keyword — the lookup path, as search_dashboards is for dashboards; list_skills is the enumeration one. Reach for this when the user names a skill or describes one (“the board-deck runbook”, “our churn procedure”) instead of listing every skill and matching the names yourself. Searches names and the one-line descriptions and ranks the hits; matching is keyword/substring based, so one distinctive word works best and a multi-word query ranks skills matching more of the words higher. Rows are list_skills rows — id, name, description, ownerId/ownerName, updatedAt — and the id is what you pass on to get_skill: a skill’s NAME MAY REPEAT (two skills can legitimately share one), so never resolve a skill by name. RANK ORDER IS NOT IDENTITY: when several hits tie at the top score with near-identical names the response carries a hint saying so — confirm which one is meant (get_skill, or ask the user) before acting on it. Returns only the skills YOU may open (per-skill grants + the workspace default; a guest needs a grant), and never archived ones. If nothing matches, the skill may live in a DIFFERENT workspace (search each from list_workspaces before concluding it doesn’t exist), or call list_skills and match semantically yourself (workspaces are small).
get_skill
Read-only
Return one skill in full, including the markdown body — the instructions themselves. Identify it by id — from list_skills, or the bracketed id on a line of the workspace-skills catalog. A skill’s name is a label and may repeat, so the id is the only handle; never guess one from a name. Load the body BEFORE planning the work it covers and follow its procedure rather than improvising an equivalent one — it is the workspace’s own answer to that task, and the caveats in it are usually the point. editing is present when a member has the skill open in the web editor (their name and when they last touched it), meaning the text may change under you. Pass format:‘markdown’ to get the skill back as a ready-to-write SKILL.md file instead of JSON — YAML frontmatter (name, description) followed by the body, byte-identical to the file the web Download button produces. That is the LOAD-INTO-MY-LOCAL-CLIENT case: write the returned text verbatim to .claude/skills/<name>/SKILL.md (or wherever your client keeps skills) and it works there as it does here. Keep the default format:‘json’ for reading or editing a skill — the markdown carries only name, description and body, not the id, versions, or edit lock. Requires view access on that skill (owner, a grant, or the workspace default; guests need a grant).
save_skill
Destructive write
Create or update a workspace skill — how you REMEMBER a procedure the user asks you to keep (“always chart revenue this way”, “here’s how we do the weekly review”): write it as a skill instead of answering that you’ll remember it. Omit id to create; pass the id from list_skills to update in place. Write it as a runbook for a colleague who knows the tools but not this workspace: name short (a display label, not an identifier — a duplicate name is allowed and the id stays the handle), description ONE line saying when to use it (that line is the ONLY text a future agent sees before deciding whether to load the skill, so make it a trigger, not a title restatement), body markdown with the actual steps, max 20000 characters. Pass expectedUpdatedAt (the updatedAt you read from get_skill) to make the write conditional — it refuses rather than overwriting if someone changed the skill in the meantime; without it, last writer wins. Refuses while another member has the skill open in the web editor, naming them. archived: true RETIRES a skill (it leaves list_skills, the catalog agents read, and the in-app skill menu) without deleting it — prefer that to delete_skill for anything that might be wanted again; archived: false restores one. An archived skill refuses content edits, so pass archived: false alongside the new text to restore and edit in a single write. Returns id, updatedAt. Creating needs full workspace membership; updating needs edit access on that skill (owner, editor grantee, or the editor default).
save_skill_version
Additive write
Seal the skill’s current name, description and body as a recorded version RIGHT NOW, instead of waiting for the automatic capture (an edit seals itself after a quiet period). Use before you rewrite someone else’s skill substantially, so there is a known-good point to roll back to. Returns written:false when the current text already matches the latest version — that is success, not an error. get_skill lists the recorded versions (rev + when + why); restore_skill_version rolls back to one. Requires edit access on the skill.
restore_skill_version
Destructive write
Roll a skill’s name, description and body back to a recorded version (rev from get_skill’s versions). Use when an edit made a skill wrong and an earlier version was known good. The current text is sealed as a version FIRST, so a restore is itself reversible — the response’s rev is that safety version, the one to pass back here to undo the rollback (null when the current text already matched the latest version). A restore can change the skill’s name back; its id never moves. Refuses while another member has the skill open in the web editor, and refuses an archived skill (restore it with save_skill archived:false first). Requires edit access on the skill.
delete_skill
Destructive write
Delete a workspace skill permanently. There is no undo and no restore, so prefer editing it with save_skill unless the user explicitly wants it gone. Confirm with the user only when their request does NOT identify the skill unambiguously; when the request names it, or you resolved the id from list_skills and it matches what was asked for, that request IS the confirmation. Names may repeat, so when one name resolves to more than one id, ask which before deleting. Only the skill’s OWNER (ownerId, which transfer_ownership moves — the author until then) or a workspace admin may delete one.
set_skill_access
Destructive write
Grant, change, or revoke access to ONE workspace skill — the write path for a skill’s sharing, mirroring the web’s Skill → Sharing pane. Two independent knobs, at least one required: memberId + role sets a NAMED grant (‘editor’ | ‘viewer’, or ‘none’ to remove that person’s grant), and workspaceDefault sets the baseline every full member gets without one — ‘none’ (named people only), ‘viewer’ (everyone in the workspace can read it), or ‘editor’ (everyone can edit it, which is what a skill is born with). This is how a request_skill_access request is ANSWERED: grant the requester editor, which also clears the pending request. Who may call it: anyone with edit access on the skill (its owner, an editor grantee, or a workspace admin); it refuses an archived skill (restore it first with save_skill archived:false). memberId must already be a member of this workspace (invite_member first) and may be neither the skill’s OWNER — the owner already holds every right, and ownership moves only through transfer_ownership — nor YOURSELF: ask the owner or a workspace admin to change your own access rather than removing it by accident. A GUEST (share-by-email) can hold a grant and read the skill, but a guest’s role is capped at viewer whatever is stored, so an editor grant on a guest is INERT until they are promoted to a full member. This writes the grants map and nothing else — it never touches the skill’s text and never moves updatedAt, so it cannot collide with someone editing in the web app or invalidate an expectedUpdatedAt you are holding. Returns the skill’s ownerId (never a grant — it lives outside the map) and the grants as they now stand.