skills: Add project-specific skill library.
This commit is contained in:
53
.claude/skills/setup-skills/LOCKFILE.md
Normal file
53
.claude/skills/setup-skills/LOCKFILE.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Skills Lockfile
|
||||
|
||||
`.claude/skills-lock.yaml`, at the root of a project, tracks which library
|
||||
skills (from `~/.claude/skills/library/`) have been copied into that
|
||||
project's `.claude/skills/`, so [`setup-skills`](SKILL.md),
|
||||
[`update-skills`](../update-skills/SKILL.md), and
|
||||
[`remove-skills`](../remove-skills/SKILL.md) all agree on what's installed
|
||||
without re-deriving it from the filesystem.
|
||||
|
||||
## Schema
|
||||
|
||||
A YAML list of entries, one per installed skill:
|
||||
|
||||
```yaml
|
||||
- name: nbdev
|
||||
hash: 3f2a9b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a
|
||||
- name: terraform-conventions
|
||||
hash: 9c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a3f2a9b
|
||||
```
|
||||
|
||||
- `name` — matches both the skill's directory name in the library
|
||||
(`skills/library/<name>`) and its copied directory name in the project
|
||||
(`.claude/skills/<name>`).
|
||||
- `hash` — the output of `hash-dir.sh` run against that one skill's
|
||||
directory contents, recorded at the moment it was last copied or
|
||||
confirmed up to date. Never a hash of anything else — not the whole
|
||||
project, not the whole library, just that one skill's own directory
|
||||
tree.
|
||||
|
||||
## What a mismatch means
|
||||
|
||||
To classify a skill's state, compare three values: the lockfile's stored
|
||||
`hash`, `hash-dir.sh` on the project's current copy
|
||||
(`.claude/skills/<name>`), and `hash-dir.sh` on the library's current
|
||||
source (`~/.claude/skills/library/<name>`).
|
||||
|
||||
| stored vs. project copy | stored vs. library source | meaning |
|
||||
|--------------------------|----------------------------|--------------------------------------|
|
||||
| match | match | nothing to do |
|
||||
| match | differs | library moved on — safe to update |
|
||||
| differs | match | project customized on purpose — leave it |
|
||||
| differs | differs | conflict — report, don't touch |
|
||||
|
||||
## Writing to the lockfile
|
||||
|
||||
- Adding a skill: append a new `{name, hash}` entry.
|
||||
- Applying a safe update: overwrite that entry's `hash` in place with the
|
||||
library's current hash.
|
||||
- Removing a skill: delete its entry entirely.
|
||||
|
||||
Never reorder or restructure existing entries beyond what an add, update,
|
||||
or remove requires — this file is meant to diff cleanly in a project's
|
||||
git history.
|
||||
46
.claude/skills/setup-skills/SKILL.md
Normal file
46
.claude/skills/setup-skills/SKILL.md
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: setup-skills
|
||||
description: Add relevant skills from the shared skills library to the current project.
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Adds opt-in, project-specific skills from `~/.claude/skills/library/` into
|
||||
the current project's `.claude/skills/`, tracked in
|
||||
`.claude/skills-lock.yaml` (see [LOCKFILE.md](LOCKFILE.md) for its schema).
|
||||
Only ever adds — checking already-installed skills for updates is
|
||||
[`update-skills`](../update-skills/SKILL.md)'s job, not this one's.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Read `.claude/skills-lock.yaml` in the current project, if it exists.
|
||||
Note every skill name already listed — these are already installed and
|
||||
must not be re-proposed.
|
||||
|
||||
2. List every skill under `~/.claude/skills/library/*/SKILL.md` and read
|
||||
each one's `name` and `description`.
|
||||
|
||||
3. Inspect the current project (file tree, manifests like
|
||||
`pyproject.toml`/`package.json`, file extensions present, etc.) and
|
||||
judge which library skills — excluding ones already installed — seem
|
||||
relevant, the same way you'd reason about any unfamiliar codebase.
|
||||
Propose that shortlist to the user with your reasoning, one line per
|
||||
skill. If the user asks to see the full catalog instead, list every
|
||||
library skill (minus already-installed ones) with its description.
|
||||
|
||||
4. Let the user confirm, adjust, or pick freely from the full list.
|
||||
|
||||
5. For each confirmed skill:
|
||||
- If `.claude/skills/<name>/` already exists in the project and is
|
||||
*not* in the lockfile, skip it and tell the user why (a same-named
|
||||
skill already lives there and isn't tracked — remove or rename it
|
||||
first if they want the library version).
|
||||
- Otherwise, copy `~/.claude/skills/library/<name>/` to
|
||||
`.claude/skills/<name>/` in the project, run
|
||||
`~/.claude/skills/setup-skills/hash-dir.sh .claude/skills/<name>`,
|
||||
and append `{name, hash: <output>}` to `.claude/skills-lock.yaml`
|
||||
(create the file, an empty YAML list, if it doesn't exist yet).
|
||||
|
||||
6. Report what was added and what was skipped, and why.
|
||||
|
||||
Done when every confirmed skill is either copied and recorded in the
|
||||
lockfile, or explicitly skipped with a stated reason.
|
||||
23
.claude/skills/setup-skills/hash-dir.sh
Executable file
23
.claude/skills/setup-skills/hash-dir.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deterministic recursive hash of a directory's file contents.
|
||||
#
|
||||
# Hashes relative paths, not absolute ones, so two directories with
|
||||
# identical contents hash identically regardless of where they live on
|
||||
# disk (needed to compare a project's copied skill against the library
|
||||
# source it was copied from).
|
||||
#
|
||||
# Usage: hash-dir.sh <directory>
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: hash-dir.sh <directory>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir="$1"
|
||||
if [ ! -d "$dir" ]; then
|
||||
echo "Not a directory: $dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(cd "$dir" && find . -type f -print0 | sort -z | xargs -0 -r sha256sum) | sha256sum | awk '{print $1}'
|
||||
Reference in New Issue
Block a user