| name | skill-overlap |
| description | Flag content-redundant SKILL.md pairs as merge candidates — pairwise body cosine similarity over the skill pack, sorted highest-first. Use when the pack feels bloated or two skills seem to overlap, to find "skills A and B are N% token-similar — consider merging" candidates before a skill-lifecycle archive pass. Proposal only — never merges, edits, or deletes a skill. |
/skill-overlap — flag content-redundant SKILL.md pairs (never merge)
The one context-cost technique from the Comet/Perplexity writeup that fak did
not already cover (#3930): skill-to-skill content redundancy.
skill-lifecycle archives dead skills and
clean-skill trims fat ones — neither measures
whether two live skills say the same thing. With 55+ SKILL.md files (many
*-score scorecards), that overlap is where the pack quietly bloats.
This skill measures it and stops. Max action is to PRINT candidates for a
human to judge — like skill-lifecycle's dry-run archive verdicts, it proposes,
it never merges. Deciding two skills are genuinely one is a semantic call the
detector deliberately does not make; there is no --apply.
The witnessed helper
skill_overlap.py runs a pairwise token-similarity primitive over every
.claude/skills/*/SKILL.md body and emits the pairs above a threshold,
sorted by similarity:
python .claude/skills/skill-overlap/skill_overlap.py [--threshold T] [--top N] [--json]
- Front-matter is stripped first — the shared
name:/description: YAML
skeleton is structural, not redundant, so it must not inflate the score.
- Similarity is body cosine over token frequency with a small function-word
stoplist — "skills A and B are N% token-similar" in the issue's own words. Same
posture as
fak dup / fak traj (block- and query-level near-dup detection),
self-contained so the witness runs with no built fak binary.
- Default threshold 0.5; drop to
--threshold 0.4 to see the long tail.
shared_top names the highest-weight tokens both bodies carry — the why
behind each score, so a human can judge the merge without re-reading both.
Exit code is always 0: this is advisory, and "no candidates" is a clean answer.
How to read a candidate
A high score means lexical overlap, not that a merge is correct. Two *-score
scorecards may share vocabulary (debt, scorecard, commit) yet tend
genuinely different surfaces. Before proposing a merge:
- Read both
SKILL.md bodies. Do they tend the same surface, or just share
the scorecard idiom?
- If genuinely redundant → open an issue proposing the merge, or route the
weaker one through
skill-lifecycle to archive
(reversible), never a raw delete.
- If distinct-but-similar → the overlap is a discoverability smell; sharpen
each
description:'s "Use when…" trigger via skill-score
so the two stop colliding in recall.
Witness
python .claude/skills/skill-overlap/skill_overlap_test.py — a fixture skill
pack with one deliberately-overlapping pair asserts that pair is surfaced above
the threshold while two unrelated skills are not, plus the front-matter-stripped,
proposal-only, deterministic, and archived-skip invariants. This is the skill's
proof-of-correctness; run it after any change to the detector.