[Feature]: `skills install` / `skills sync` command to install skills from lock file
Problem
Hey there, first off thanks for building skills — it’s a really nice abstraction!
I’ve been digging into the lock file behavior, hoping it might offer something like a “reproducible state” mechanism across machines.
Current behavior (as I understand it)
The global lock file lives at
~/.agents/.skill-lock.jsonand has the shape defined insrc/skill-lock.ts(and redefined insrc/cli.ts):skills: Record<string, SkillLockEntry>keyed by skill name- Each
SkillLockEntrystores:source(normalized identifier, e.g.owner/repo)sourceType(github,mintlify,huggingface,local, …)sourceUrl(the URL actually used withskills add)- optional
skillPath skillFolderHash(GitHub tree SHA for the skill folder)installedAt/updatedAttimestamps
Global installs (via
runAddinsrc/add.ts) update the lock file by callingaddSkillToLock, which writes/updates an entry for the installed skill.skills check(runCheckinsrc/cli.ts):- Reads the lock file.
- Builds a
CheckUpdatesRequestusing only entries that have askillFolderHash. - POSTs to
https://add-skill.vercel.sh/check-updates. - Prints which skills have updates available, but does not install or modify anything.
skills update(runUpdateinsrc/cli.ts):- Does the same lock-file →
CheckUpdatesRequest→ API call. - If there are updates, it reinstalls only those updated skills, using the
sourceUrland skill name from the lock entry:- Roughly:
npx -y skills <entry.sourceUrl> --skill <name> -g -y.
- Roughly:
- It does not attempt to install all skills in the lock file, only those whose
skillFolderHashdiffers from the server’slatestHash.
- Does the same lock-file →
Listing actual installed skills is done via the filesystem (e.g.
.agents/skills/<skill-name>and agent-specific directories ininstaller.ts/list.ts), not via the lock file.
So the lock file is currently acting as a global registry + update-tracking database, rather than a declarative “install manifest” like package.json or a fully deterministic package-lock.json.
Pain point
Because the lock file is global and already contains:
- the skill names,
- the original
sourceUrlused to install, - and the provider/path information,
it feels like the perfect place to drive reproducible installs across machines or after deletion.
However, in practice:
If I sync only
~/.agents/.skill-lock.jsonvia dotfiles onto a new machine:skills checkandskills updateon that machine can now see those skills and their hashes.- But
skills updatewill only reinstall skills that the API considers “out of date”. If the storedskillFolderHashalready matches the remote hash, that skill is not included inupdates, so it does not get reinstalled—even if it’s completely missing on disk on that machine.
There is currently no command that says “install everything from this lock file”.
- So I can’t use the lock file as a true manifest for:
- setting up a new dev machine, or
- restoring skills after a cleanup, or
- keeping multiple machines in sync using just dotfiles.
- So I can’t use the lock file as a true manifest for:
Right now, I’d need to manually re-run npx skills add ... for each repository, or write my own script around the lock file structure.
Proposed Solution
I’d love a first‑class command, something like:
skills install(orskills sync,skills restore, etc.)
that:
Reads
~/.agents/.skill-lock.json(and/or a project-local lockfile, if that ever exists).For each entry in
lock.skills:Uses
entry.sourceUrlandnameto reinstall that skill via the existing CLI pipeline, e.g.:# Conceptually npx skills <entry.sourceUrl> --skill <name> -g -y
Optionally supports some modes/flags, for example:
--missing-only: only install skills that are not currently present on disk (according toinstaller.ts/listInstalledSkills).--all: reinstall everything in the lock file regardless of hash (useful for a completely fresh machine).--dry-run: show what would be installed/reinstalled, using lock entries as the source of truth.
This would provide:
- A reproducible global skill set across machines by simply:
- syncing
~/.agents/.skill-lock.jsonvia dotfiles, and - running
npx skills installon a new machine.
- syncing
- A way to recover from manual deletions of skill directories without having to remember all original
skills addcommands.
And this fits the design because:
- The lock file already holds everything needed to reconstruct the install command:
sourceUrl(exact URL originally used),source/sourceType/skillPath(for future flexibility),- and the skill’s logical name (the key in
lock.skills).
skills updatealready uses this data to drive a reinstall step for updated skills.skills install/syncwould just generalize this from “only updated skills” to “all skills (or all missing skills) in the lock file”.
- It keeps the mental model cohesive:
skills add: install new skills and write them to the lock file.skills check: read lock file to detect which tracked skills could be updated.skills update: read lock file + update only out-of-date skills by reinstalling.skills install/skills sync: read lock file + ensure all tracked skills are present on the local machine.
Alternatives Considered
No response
Additional Context
Possible open questions
Some questions I’m not presuming to answer, but worth considering:
- Should
skills install:- only operate on global skills (current lock file), or
- support a future project-level lock file as well?
- How should it behave if:
- the lock file references a skill whose repo is now gone or private?
sourceUrlhas changed or is invalid?
- Should it integrate with
listInstalledSkillsto detect “missing” skills more robustly?
Source: vercel-labs/skills