Role
You are the update-and-distribution loop for installed agent skills. Skills
are installed as folder copies (global: ~/.agents/skills/; project:
<repo>/.agents/skills/) with symlinks in the matching .claude/skills/
directory — so editing or pulling the library repo does not update any
install. You close that gap: find every install in scope, work out which
skills are stale, report, and (with approval) update them through the right
mechanism.
Read references/lock-formats.md before acting — it defines the install
layouts, the two lock-file formats (they are different artifacts), and the
decision table mapping each skill state to its update path.
Trigger Conditions
Invoke when the user asks to:
- update installed skills ("update my skills", "get the latest skills")
- check for skill updates without applying them
- roll library changes out everywhere ("update all repos that use these skills") — fleet mode, over a root folder they name
- audit or inventory where skills are installed / whether installs drifted
Do NOT invoke for: installing a new skill (that is find-skills /
npx skills add), fixing a defective skill (that is skill-feedback), or
editing skill content in the library repo (ordinary development work).
Input
| Parameter | Required | Description |
|---|---|---|
scope |
Yes | global, project, fleet, or any combination. Default when unstated: global + the current repo if it has an install. |
root_folder |
fleet only | Folder to walk for repos with installs (e.g. ~/s). Always confirm this path with the user before scanning. |
mode |
No | check (report only, default) or update (report, then apply after approval) |
library_path |
No | Local checkout of the skill library. Default: the current repo if it is the library (has skills/ + skills-lock.json), else ask. Without it, drift detection is skipped and only lock-tracked GitHub updates are possible. |
skills |
No | Restrict to named skills; default all |
The Two Update Paths
- CLI path —
npx skills check/npx skills updatefor skills tracked in.agents/.skill-lock.json. Compares the recorded git tree hash against GitHub, so it only sees pushed content. This is the only permitted path for skills from external sources (not in the library checkout). - Local-sync path —
scripts/skill_update_scan.py synccopies the library checkout's version over the installed copy and repairs the.claude/skillssymlink. For untracked installs, and for when the local library is ahead of GitHub. Never rewrites the lock file, and refuses skills that are not in the library.
Workflow
Step 1 — Resolve Scope and Library
Establish which installs are in scope (global / project / fleet) and locate the library checkout. If fleet mode, confirm the root folder with the user before walking it. Check library freshness:
git -C {library_path} status --porcelain # uncommitted changes?
git -C {library_path} fetch --quiet 2>/dev/null; \
git -C {library_path} rev-list --count @{u}..HEAD # commits ahead of origin
If the library is ahead of origin, say so up front: the CLI path would install older content than the local checkout, so local sync (or pushing first) is the correct route for library skills.
Step 2 — Inventory and Drift Scan
Run the scan script (all scopes can be combined in one call):
python3 {skill_dir}/scripts/skill_update_scan.py scan \
--global \
--project {repo_path} \
--root {root_folder} \
--library {library_path} --json
This classifies every installed skill: in-sync, drifted,
untracked-external, direct-copy, external-link, broken-link, plus a
missing/broken .claude link flag.
Step 3 — Check GitHub Freshness
For lock-tracked skills, also ask the CLI what GitHub has:
npx skills check # in $HOME for global scope
(cd {repo_path} && npx skills check) # per project with a lock file
Step 4 — Report
Present one consolidated table before touching anything — in fleet mode, grouped per repo:
| Location | Skill | State | Source | Action |
where Action is drawn from the decision table in
references/lock-formats.md (CLI update / local sync / reinstall via add /
remove broken link / leave alone). If mode: check, stop here.
Step 5 — Apply Updates (approval gate)
Ask the user to approve the plan (in fleet mode, per repo or all-at-once — their choice). Then:
# CLI-tracked skills with GitHub updates
npx skills update -g -y {skill…} # global scope
(cd {repo_path} && npx skills update --project -y {skill…})
# Drifted or untracked library skills
python3 {skill_dir}/scripts/skill_update_scan.py sync \
--global --library {library_path} --all-drifted
python3 {skill_dir}/scripts/skill_update_scan.py sync \
--project {repo_path} --library {library_path} {skill…}
Remove broken .claude/skills symlinks only after listing them and getting
approval.
Step 6 — Verify and Summarise
Re-run the Step 2 scan; everything actionable should now be in-sync (or
tracked and current). Report:
## Skill Update Summary
**Scope:** {global / project / N repos under root_folder}
**Library:** {path} @ {commit} {(+N unpushed)?}
**Updated via CLI:** {list or none}
**Updated via local sync:** {list or none} {(lock entries now stale — reconciled on next `npx skills update`)?}
**Left alone:** {external / plugin-managed skills}
**Still needing attention:** {list or none}
Fleet Mode Notes
- The scan script walks at most 3 directory levels below the root and prunes
node_modules,.git, build dirs, and virtualenvs — a repo with installs deeper than that must be passed explicitly with--project. - Repos whose
.claude/skillsentries are plugin symlinks (targets outside.agents/skills/) are reported asexternal-linkand never modified. - Batch the report per repo; do not interleave.
Boundaries
- This skill does NOT install new skills — route to
find-skills/npx skills add. - This skill does NOT edit skill content, in the library or in installs; it only replaces installed copies with the library's current version.
- This skill does NOT hand-edit any
.skill-lock.json— the CLI owns it. - This skill does NOT update externally sourced skills via local sync, ever — CLI path only.
- This skill does NOT apply changes without the Step 5 approval gate;
checkmode never mutates anything.