Core concepts

Library and Marketplace

The Library is what is on this machine. The Marketplace is what your team has published. The two are joined by identical bytes and by nothing else.

The Library: skills on this machine

The Library reads local files and nothing else. It never fetches, never prompts and never writes. It scans two kinds of root:

  • Global: ~/.claude/skills (%USERPROFILE%\.claude\skills on Windows).
  • A project you registered: <project>/.claude/skills, for every folder you added with project add.
npx -y terum-skills@latest project add <path>
npx -y terum-skills@latest ls --local

The folder you are standing in is never scanned. A project is in the Library because you added it, and for no other reason. Only real directories directly under a root count: a symlinked skill folder, or one containing a symlink, is refused, and a plain file is not a skill.

Each row gives the name, state and path, plus the team version with identical bytes (if any), the team’s receipt for those exact bytes, your local receipt, and whether the skill is enabled.

The states a folder can be in

The states are independent, so a folder can be placed, modified and disabled at once.

StateWhat it means
Placedinstall copied a team version here and recorded a ledger row: uuid, team, version, scope, date, and a fingerprint of what it wrote.
AdoptedThe folder was already here and install --adopt <path> recorded it. The ledger row is written; no bytes are copied.
Local-onlyNo ledger row and no matching team version. It exists on this machine and nowhere else.
ModifiedPlaced, but its fingerprint no longer matches the ledger. Any later removal moves it to ~/.terum/skills/quarantine/ instead of deleting it.
DisabledClaude Code’s skillOverrides setting says off for that name. The folder stays on disk; Claude does not load it.

The ledger is the only authority for a path this tool may delete. Disabled is Claude Code’s own setting, not a Terum one: skill disable and skill enable write the same key as Claude Code’s /skills menu, so the two never disagree.

The Marketplace: what the team published

npx -y terum-skills@latest ls

This reads the team clone as it stands and does not fetch; run sync first for the current state. Each skill shows:

  • Newest version: the highest v<N> folder, sorted numerically, so v10 is newer than v2.
  • Author: metadata.author from the newest version’s SKILL.md, as Name <email>.
  • Category: metadata.terum-category from the same file.
  • Installs: how many teammates list the skill in installed[], once per person, archived members included.
  • Projects: the team projects that list the skill. A skill in no project is still shared; the version folder is the shared copy.
  • Verdict: from the newest usable committed receipt. When the latest version has none, an older version’s score is shown and marked as not current.

The app’s Marketplace opens on a shelf titled Top rated. It sorts by install count, not by eval result, so read it as the most-installed skills and the row’s verdict as the score.

How the two lists are linked

By identical bytes. Both sides compute the same content digest, and a Library folder joins whichever committed version digests the same. The name is not consulted: a renamed folder still matches, and two folders with the same name but different content do not.

Folders on this machine join team versions by identical bytes, and an edit breaks the join.

That is why an edit detaches the score. Change one character in a placed skill and its digest changes. No committed version has those bytes, so the matched version and the team’s receipt drop off the row, and the row is marked stale. Nothing is lost: the team’s version and receipt are where they were, and publishing your edit mints the next version with its own score.

When identical bytes exist in more than one team and no placement decides which, the row is reported as ambiguous rather than guessed.

Team projects and library projects

Two things that share a word.

Team projectLibrary project
Lives inteam.json, sharedconfig.json, this machine
IsA named list of skill uuids, plus the git remotes its skills belong inA folder whose .claude/skills the Library scans
Created byteam project createproject add <path>
Used forGrouping published skills, and install project <name>Finding local skills, and choosing where to install

They meet in one place: install project <name> defaults its destination to the registered folder whose origin matches one of that team project’s remotes, if exactly one does. Every other install defaults to Global.

Profile and installed

Your people file carries two lists. installed[] means a copy is on a machine; install writes it and uninstall-skill removes it when the last local copy at that scope goes. profile[] means you stand behind the skill; publish and install add the entry, one per skill, and profile --remove <skill> takes it off.

install member <handle> installs that person’s profile[], not their installed[]: what they endorse, not everything they happen to have.

Categories

A new team starts with debugging, testing, docs, workflow, research, infra and misc in team.json. The list is advice: an off-list category prints a warning and publish continues.

A skill’s category is metadata.terum-category in its SKILL.md, and it is part of the digest, so changing it mints a new version on the next publish. When the file declares none, publish uses --category <name> if you passed it, otherwise asks claude --model haiku to pick from the team’s list, and falls back to misc. It writes the result into your SKILL.md.

Full reference on GitHub