Publish a skill
Publishing copies one folder from your Library into the team repository as its next immutable version. It is the only way a skill reaches the team, and it runs only when you type it.
One verb writes skills to the team
npx -y terum-skills@latest publish <skill-or-path>The ref is a skill name or a path, and either must resolve inside your Library (Global plus every project you registered), so publish can never be pointed at an arbitrary folder on disk.
Nothing else in the tool creates a version, and the push guard in your clone refuses a hand git push of skill bytes.
Before you publish
- The folder is in your Library. Under Global, or in a registered project. See Install and manage.
- This machine has joined a team. Run
setup <org>/<repo>first; a machine that never completed a join is refused. - The folder passes hygiene.
validatereports every finding, offline.skill fixrepairs the mechanical ones, such as YAML quoting, and lists what still needs you.
npx -y terum-skills@latest validate <path>
npx -y terum-skills@latest skill fix <path>On a folder that has never been published, validate also reports the four managed fields as missing. Publish writes those itself, so that finding does not block it. See Hygiene checks.
What publish does
Fetch
The team clone is fetched and hard reset to
origin/mainunder the clone’s writer lock. If another terum-skills command holds the lock, publish waits a short while for it.Read the folder
Every file is read, eval assets included. A folder that is a symlink, contains one, or has no
SKILL.mdis refused.Resolve the category
The category your
SKILL.mddeclares wins, then--category <name>, then oneclaude --model haikusuggestion matched against the team’s list, thenmisc. The model cannot add a category, and publish never blocks on it.Inject the managed fields
An in-memory copy of
SKILL.mdgetslicense(the team’s policy),metadata.id(the uuid the repository already holds for this name; a new name keeps a declared id no other skill uses, or gets a fresh one),metadata.author(Name <email>from your identity) and the category, when the file declares none.Hygiene
The checks run on the injected copy and every other file. An error refuses the publish; a warning is printed and gates nothing.
The regression gate
If your newest local eval receipt of these exact bytes is a
FAIL, publish asks whether to publish anyway. Having no receipt never blocks, and this step reads only your machine.Write to the team
The injected
SKILL.mdis written back to your folder after the last question, so a canceled publish leaves it untouched. Then one commit goes straight tomain: a newskills/<name>/v<N>/unless an existing version holds these exact bytes, the skill’s eval assets, and every local receipt of these bytes.--project <name>also adds the skill to that team project’s list.Your profile entry
The skill is added to your profile without a question, because typing
publishis the endorsement.profile --remove <skill>takes it off and unpublishes nothing.
A run ends one of two ways, and both are successes. Either a version was minted:
Published deploy-check as Version 4 to the acme marketplace. Attached 2 eval run(s).Or the bytes match an existing version, so nothing is minted, though eval assets and matching receipts still travel. When nothing moved at all, the line starts Nothing to publish:.
What publish never does
- It opens no pull request. Every write is a direct commit to
main, whatever the verb’s help text says. - It checks no ownership. Anyone in the team can publish any name, and a folder whose name the team already has becomes that skill’s next version. Before appending, publish checks that the name still carries the uuid it resolved, and refuses if it changed hands in the meantime.
- It does not install. Nobody’s machine gains a copy because you published.
- It sends nothing to Terum. The category suggestion goes to Anthropic through your
claude; the bytes go to your git host.
Republishing
After an edit. Change any file and the content digest changes, so the next publish mints the next version. Older versions stay exactly as they were: nothing can change what Version 3 is. See Versions and identity.
After an eval-only change. Eval cases live in evals/, which the content digest leaves out. The next publish mints no version, writes the eval assets and attaches matching receipts, which is how an eval reaches the team without moving a skill byte. When eval generates assets it says the next publish mints a new version; it does not.
Changing a category. publish --category fills a category in and never replaces a declared one. To change it, edit the folder:
npx -y terum-skills@latest skill category ~/.claude/skills/deploy-check --to opsThat rewrites one field locally and touches nothing else. The team shows the old category until you publish again, which mints a new version because the category is part of the content.
Unpublishing
npx -y terum-skills@latest unpublish <skill>The argument is the skill’s name in the Marketplace. Anyone in the team may unpublish any skill, with no approval, so whoever notices a wrong publish can retract it. The brake is typing the skill’s name to confirm; --yes skips it.
Unpublish removes every version of the skill for everyone, in one commit: the version folders, their eval assets, every attached receipt, and the skill’s entry in every team project and every member’s profile.
What stays: installed copies keep working until each machine runs sync, which then reports the skill as removed from the team. The git history is not rewritten, so the bytes remain reachable in old commits. installed[] records are left alone, because they describe machines, not the repository.
Unpublishing does not reserve the name. Publishing the same folder later starts again at v1, and it keeps the metadata.id your SKILL.md carries unless another published skill holds it.
Full reference on GitHub
- Publish a skilldocs/guides/publish.md
- Versions and identitydocs/concepts/versions-and-identity.md
- Hygiene checksdocs/evaluating/hygiene.md