# 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`.

```sh
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.

| State | What it means |
| --- | --- |
| Placed | `install` copied a team version here and recorded a ledger row: uuid, team, version, scope, date, and a fingerprint of what it wrote. |
| Adopted | The folder was already here and `install --adopt <path>` recorded it. The ledger row is written; no bytes are copied. |
| Local-only | No ledger row and no matching team version. It exists on this machine and nowhere else. |
| Modified | Placed, but its fingerprint no longer matches the ledger. Any later removal moves it to `~/.terum/skills/quarantine/` instead of deleting it. |
| Disabled | Claude 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

```sh
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.

::: figure library-marketplace
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 project | Library project |
| --- | --- | --- |
| Lives in | `team.json`, shared | `config.json`, this machine |
| Is | A named list of skill uuids, plus the git remotes its skills belong in | A folder whose `.claude/skills` the Library scans |
| Created by | `team project create` | `project add <path>` |
| Used for | Grouping 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`.
