Use when a vault holds a library of notes about Claude Code skills and it has drifted from the skills that actually exist. Trigger phrases - "sync the skill library", "is the skill library up to date", "check the skill library", "which skills are missing from the vault", "update the skill notes". Also trigger when the user mentions a skill they built that has no note, an index that no longer matches its folder, or notes pointing at plugin paths that have moved. This skill reads the real inven...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add neckarshore-skills/obsidian-vault-autopilot --skill skill-library-sync --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Skill Library Sync?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/neckarshore-skills-skill-library-sync)More formats (shields.io, HTML) on the badges page.
---
name: skill-library-sync
status: beta
description: Use when a vault holds a library of notes about Claude Code skills and it has drifted from the skills that actually exist. Trigger phrases - "sync the skill library", "is the skill library up to date", "check the skill library", "which skills are missing from the vault", "update the skill notes". Also trigger when the user mentions a skill they built that has no note, an index that no longer matches its folder, or notes pointing at plugin paths that have moved. This skill reads the real inventory from named sources only - it never searches the filesystem for skills.
---
# Skill Library Sync
Reconcile the vault's Skill Library against the skills that actually exist: the
user's own skills, the installed plugins, and the repositories named in the
config. Create what is missing, re-locate what moved, retire what is gone.
The core principle - a library maintained by hand drifts at exactly the rate the
estate grows, and nothing detects it. Scan the ground first, show the difference,
write only after the user confirms.
## Principle - Core + Nahbereich + Report
- **Core:** reconcile the library against the inventory.
- **Nahbereich:** the index note's generated section - everything from its first
`## ` heading down - is rebuilt from the library on every `--write` run, so
dead wikilinks in its table disappear on their own. Its frontmatter, its H1
and any intro prose above that first heading belong to the user and are
carried through verbatim, a stale count in them included. Do not hand-edit
that zone to correct such a count - it is the one part of the index the code
deliberately protects. Nothing else. This skill does not write skill
documentation.
- **Report:** counts per bucket including the zeros, every rename by name, plus a
findings entry.
## Fences
1. **The body boundary.** Everything below `## Notizen` belongs to the user and
is never written. The placeholder stub is the one exception and is matched
byte-for-byte - never by length.
Above the boundary the split is by KEY, not by position: this skill owns
`title`, `type`, `description`, `herkunft`, `ort`, `plugin`, `status`,
`created`, `last_modified` and the two generated tags (`Claude/ClaudeCode`
and `Skill/<herkunft>`) - it derives them from the inventory, so it also
replaces them. Every other frontmatter key, and every other tag, is the
user's: carried through a rewrite verbatim, as lines, never re-serialised.
The origin tag has to be owned rather than carried, because a relocate can
change `herkunft` and a stale `Skill/<old>` must not survive.
2. **No filesystem discovery.** Only paths the config names, that
`installed_plugins.json` names, or that a library note records in its own `ort`
(fence 4). Never a tree walk, never a glob, never auto-detection. Outside the
vault this skill is read-only, always.
3. **Nothing is deleted.** A skill that vanished gets `status: entfallen` and moves
to the retired subfolder.
4. **A retirement means the skill was looked for.** Before a note is retired, the
single path that note records in its `ort` frontmatter is checked for a
`SKILL.md` - one stat call per candidate, no search, never a write. A skill
still sitting at its recorded location is never retired; it is reported as
`unverified` and left exactly where it is. This is the third named source and
it is listed here rather than left implicit: an empty `source_roots` is the
absence of evidence, not evidence of absence, and a library whose job is
telling you what you have must not use its own silence to declare five live
skills gone.
## Shared conventions
1. `../../references/vault-autopilot-note.md` - protected files and folders.
2. `../../references/findings-file.md` - the append-only findings ledger. This
skill's own ledger diverges from that convention - see "Findings" below.
3. `../../references/config-spec.md` - the `skill_library` config section.
## Step 1 - Scan
node "${CLAUDE_PLUGIN_ROOT}/skills/skill-library-sync/scripts/cli.js" scan "$OBSIDIAN_VAULT_PATH"
Prints how many skills exist and how many notes describe them. Writes nothing.
## Step 2 - Diff
node "${CLAUDE_PLUGIN_ROOT}/skills/skill-library-sync/scripts/cli.js" diff "$OBSIDIAN_VAULT_PATH"
Prints the four buckets - created, relocated, retired, renamed - plus
`unverified` and conflicts, each with a count, and names every note that would
change. Writes nothing.
`unverified` is the fence-4 bucket: notes the run declined to retire, each with
its reason. `skill-still-at-recorded-location` means the skill is on disk and
the note is right - configure a `source_root` so the inventory can see it.
`no-recorded-location` means the note itself has no `ort` to check - repair the
note.
Show this output to the user. Do not proceed without an explicit confirmation.
## Step 3 - Apply
node "${CLAUDE_PLUGIN_ROOT}/skills/skill-library-sync/scripts/cli.js" apply "$OBSIDIAN_VAULT_PATH"
node "${CLAUDE_PLUGIN_ROOT}/skills/skill-library-sync/scripts/cli.js" apply "$OBSIDIAN_VAULT_PATH" --write
`apply` without `--write` is a preview, but it is not the same preview as
`diff`: `diff` only classifies notes into buckets, while `apply` in preview
mode also runs every write-side guard (the two caps below, the library-path
checks) exactly as `--write` would. Because of that its output is shaped
differently - it cannot show the four named buckets, since some of what
would be touched may already be blocked by a guard before it is counted.
Preview mode prints:
- `planned` - the total number of notes that would be created, relocated,
retired, or renamed if you ran with `--write` right now.
- `unchanged` - notes that already match the inventory.
- `conflicts` - notes the run would refuse to touch, each named on its own
line (see diff's conflict channel).
- `warning` - printed only when `library_path` is unconfigured or the
configured directory does not exist; `--write` would refuse outright in
either case.
Only run `--write` after the user has seen Step 2's per-bucket breakdown and
confirmed.
### The two caps
Two independent ceilings guard `apply --write`, and they catch different
failure shapes:
- **Mass-change cap** - refuses when `created + relocated + retired + renamed`
exceeds a threshold. Default 200; override with `--max <n>`.
- **Retire cap** - refuses when the number of notes to retire alone exceeds
`floor(max(10, notes_read * 0.25))` - a quarter of the notes currently in
the library, floored at 10 so a small library is not blocked by rounding.
Override with `--retire-max <n>`.
Both caps exist because the mass-change cap alone does not catch "retire
nearly everything" against a library comfortably under 200 notes. Neither
number above is a fact to memorize - both are computed against the library
as it stands at run time, which is why the retire cap is stated as a formula
here rather than a number.
An empty inventory (zero skills found across every named source) refuses
outright, in both preview and write mode, before anything is classified -
an empty inventory would make every existing note look retired, and that
combination is never a legitimate sync outcome.
### Exit codes
- `0` - success (scan, diff, or a completed apply).
- `1` - a refusal: the mass-change cap, the retire cap, or the empty-inventory
guard. The run understood the situation and declined; nothing was written.
- `2` - a guard error (`library_path` unconfigured, or the configured
directory does not exist) or a usage error (missing command/vault, an
unknown flag, a missing or non-numeric `--max`/`--retire-max` value). The
run was misconfigured or malformed rather than merely declined.
Every refusal and guard error prints its message to stderr.
## Report
## Skill Library Sync Report - <date>
### Done
- Created N notes
- Relocated N notes
- Retired N notes to <subfolder>
- Renamed N notes (origin suffix)
- Declined to retire N notes (unverified - reason per note)
### Unchanged
- N notes already matched the inventory
### Findings
- <anything the user should act on>
## Findings
Every `apply --write` run appends a block to
`${OBSIDIAN_VAULT_PATH}/_vault-autopilot/findings/<date>-skill-library-sync.md`:
a `## Run HH:MM` heading, then a `counts:` list (created, relocated, retired,
unverified, renamed, unchanged, conflicts), one line per unverified note with
its reason, and one line per conflict. This records that a run
happened and what it touched - it does not classify individual findings by
severity.
That is narrower than `../../references/findings-file.md`, which specifies
per-finding `F<n>` ids, a `Class A-D` severity, `file_refs`, and frontmatter
`counts.*` updated on every append. Reconciling the two schemas is open and
is not this skill's call to make alone - the convention's frontmatter-mutation
requirement conflicts with the append-only write shape this ledger was built
to guarantee.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!