CLI reference
The CLI ships as @skill-set/cli with a single bin, skill-set. Run it without installing via npx.
npx @skill-set/cli <command> [args] [flags] [-- <args for the skills CLI>]
Resolution and installation of individual skills are delegated to the upstream skills CLI, pinned to skills@1.5. skill-set --version prints both versions:
skill-set/<version> (wraps skills@1.5, pinned)
Commands#
| Command | Usage | Does |
|---|---|---|
init | init <set> <locator> [locators...] | Scaffold a new set manifest |
add | add <url|path> | Fetch a shared set manifest, then install it |
install | install <set> | Install members, skipping ones the lock already satisfies |
build | build [<set>] [--lock] | Regenerate SKILL-SET.md files and the skill-sets.json index |
lock | lock <set> | Record each member’s installed content in a set-lock |
share | share [<set>] [--manifest <path>] [--output <dir>] | Export a shareable manifest and lock |
verify | verify <set> [--frozen] | Check installed members against the set (frozen: byte-exact) |
update | update <set> | Update members via the skills CLI, then re-lock |
remove | remove <set> | Remove a set definition, optionally remove skills not otherwise in use |
init#
skill-set init <set> <locator> [locators...]
Scaffolds .agents/skills/skill-sets/<set>/<set>.skill-set.json at version 0.1.0 with the given members, then offers to install them and generate the set files. At least one locator is required — a skill-set cannot be empty. Set names are lowercase alphanumerics with single hyphens, at most 64 characters. If a set of that name already exists, init fails; it never overwrites a set definition.
add#
skill-set add <url|path>
Acquires a shared set: fetches the manifest (HTTPS only; at most 5 redirects; 1 MiB response cap) or reads a local path, validates it against the schema and rules, prints the set summary with every member and its source, then asks for confirmation before writing anything. The fetched bytes are written verbatim as <name>.skill-set.json — the filename comes from the manifest’s name — and the normal install flow runs.
Hosts other than recognised skill-set providers prompt for confirmation before any bytes are fetched, and redirects may not hop to a new host. An existing set with the same name is an error, never a silent overwrite.
install#
skill-set install <set>
Before anything installs, every set in the project is checked for members pinned to conflicting refs — a conflict aborts with exit code 4 (see the FAQ). Members whose locked content is already on disk byte-for-byte are skipped; the rest resolve one at a time through npx skills@1.5 add <locator>. The summary reports installed, skipped, and failed counts, and any member failure makes the whole command fail after attempting the rest.
build#
skill-set build [<set>] [--lock]
Regenerates the derived files for one set, or for all sets when no name is given: a SKILL-SET.md discovery page per set (frontmatter, member table, install and provenance sections) and the project-wide skill-sets.json index. Output is deterministic — identical inputs produce identical bytes. --lock also records the set-lock, exactly as lock does.
lock#
skill-set lock <set>
Writes <set>.skill-set.lock.json: for every member, the installed skill name, its content hash (SHA-256 over the skill folder, as defined by the spec), and the resolver-reported source and ref, plus a rollup setHash for the whole set. Every member must be installed first; missing members are reported all at once.
share#
skill-set share [<set>] [--manifest <path>] [--output <dir>]
Prepares a set for distribution. It takes a local set by name or a hand-written manifest (--manifest), and offers to fill in any missing description, author, and homepage. Every member is re-fetched into a throwaway clean project and hashed there, so the exported set-lock records the content the locators actually deliver — not your local, possibly-edited skill folders. A notice names any installed skill that differs from the fetched content, and members with local-only sources cannot be shared and are reported.
The manifest and lock are written to .agents/skills/skill-sets/_share/<set>/ (or --output <dir>). Publish the two together so a recipient’s add finds the sidecar lock, or hand out a validating install command carrying the #sha256=<setHash> fragment.
verify#
skill-set verify <set> [--frozen|--no-frozen]
Two modes:
- Default — checks every member is present at its installed location and delegates a staleness check to
npx skills check(informational; its findings do not fail the verify). Content is not compared; the command says so. - Frozen (
--frozen) — recomputes every member’s content hash and compares it to the set-lock. All problems are reported in one pass — drifted members with expected and actual hashes, missing folders, and manifest/lock membership differences — and the command exits with code 3. Running--frozenwithout a lock is a precondition failure (exit 2) with a hint to create one.
In CI, frozen is the default whenever a set-lock exists; --no-frozen opts out. See verifying in CI.
update#
skill-set update <set>
Updates every member through npx skills@1.5 update <skills...> -p --yes, then re-locks the set if a lock existed and regenerates the derived files. All members must be installed before anything updates.
remove#
skill-set remove <set>
Removes the set definition — manifest, lock, and generated page — after confirmation, and refreshes the index. It then offers to also remove the set’s member skills, keeping any skill still referenced by another set (reference-counted, including by shared source). Skill removal is delegated to npx skills remove so the upstream lock stays consistent.
Global flags#
| Flag | Effect |
|---|---|
--json | Machine-readable output: exactly one JSON object on stdout |
--yes, -y | Assume yes for prompts (required where a prompt would block CI) |
--dry-run | Print what would run or be written; change nothing, spawn nothing |
--help, -h | Show help |
--version, -v | Show the skill-set version and the pinned skills version |
Arguments after -- pass through to the skills CLI verbatim, for example:
skill-set install demo -- --agent claude-code cursor
installs the set’s skills for those agents only. See npx skills --help for what the upstream accepts.
JSON output#
With --json, every run — including crashes — emits exactly one JSON envelope on stdout:
{ "ok": true, "command": "verify", "data": { "name": "frontend", "mode": "frozen", "checked": 4 } }
{
"ok": false,
"command": "install",
"error": {
"code": "ERR_SKILLSET_CONFLICT",
"message": "…",
"hint": "…",
"data": {}
}
}
error.code is a stable machine-readable code; hint and data appear when available.
Exit codes#
| Code | Meaning |
|---|---|
0 | Success |
1 | Error — anything not covered below |
2 | Usage — bad arguments, a prompt blocked without --yes, or verify --frozen without a set-lock |
3 | Drift — frozen verify found installed content that does not match the set-lock |
4 | Conflict — a member source pinned to different refs across sets |