Scan a directory or workspace for SKILL.md files across all agents and repos, capture supporting files (references, scripts, linked docs), dedupe vendored copies, enrich each Tessl tile with registry signals, and emit a canonical JSON inventory validated by JSON Schema. Then run four analytical phases in parallel against the inventory — staleness + git provenance (history, broken refs, contributors), quality (Tessl `skill review`), duplicates (similarity + LLM judgement), registry-search (per-standalone-skill registry suggestions, HTTP only) — and render a self-contained interactive HTML report with a top-of-report health overview, top-issues panel, recently-changed list, and per-tessl.json manifests view.
84
90%
Does it follow best practices?
Impact
97%
1.44xAverage score across 2 eval scenarios
Advisory
Suggest reviewing before use
Identify duplicate and overlapping skills in a discovery.json. Output conforms to duplicates.schema.json.
Hybrid phase: deterministic pre-screen (Jaccard similarity) → LLM judgement (one subagent per candidate pair, written to its own file) → deterministic clustering.
Three contracts are validated at the IO boundary:
discovery.json) and prep output (<prompts-dir>/index.json) — see duplicates-prompts-index.schema.json<verdicts-dir>/<idx>.json) — see duplicate-verdict.schema.json. Per-pair verdicts validate non-strictly: a malformed verdict from one subagent is recorded in metadata.failed_pairs[] and the run continues.duplicates.json output — see duplicates.schema.json. Malformed output exits with code 2.discovery.json produced by discover-skills.--max-pairs cap (default 10) and --allow-cross-repo (default off).python3 <skill-dir>/scripts/prepare_duplicates.py \
--discovery "$DISCOVERY_PATH" \
--prompts-dir "$PROMPTS_DIR" # default: <dirname(discovery)>/duplicates-promptsOutput:
<prompts-dir>/
├── index.json ← manifest: {metadata, items: [{idx, pair_id, skill_a, skill_b, similarity_score, prompt_filename, verdict_filename}]}
├── 000.txt ← judgement prompt for pair 0 (skill A vs skill B)
├── 001.txt ← judgement prompt for pair 1
└── ...The prep script:
discovery.skills[]--allow-cross-repo)--max-pairs (default 10), preferring pairs where both skills are agent-loaded and have higher similarity<idx>.txtindex.json linking each idx → pair_id → prompt path → expected verdict pathFor each items[i] in index.json, dispatch a subagent. Default --max-pairs is 10, so this is a single batch — issue ALL of them in one assistant message via parallel Task tool calls. Don't sub-batch ("first 10, then next 10") — there's nothing to batch.
Pass each subagent:
<prompts-dir>/000.txt)<verdicts-dir>/000.json)The subagent must:
{
"pair_id": "p001",
"verdict": "duplicate" | "overlapping" | "independent",
"reason": "<one-sentence>",
"dominant": "<skill_id_a | skill_id_b | null>"
}Failure handling: if a subagent fails to write or writes malformed JSON, retry that one. If still malformed, leave the file missing — finalize records it in metadata.failed_pairs[].
Verdicts directory (default <dirname(discovery)>/duplicates-verdicts/) — pre-create:
mkdir -p "$VERDICTS_DIR"python3 <skill-dir>/scripts/finalize_duplicates.py \
--prompts "$PROMPTS_DIR" \
--verdicts "$VERDICTS_DIR" \
--output "$OUTPUT_PATH" # default: <dirname>/duplicates.jsonThe finalize script:
index.json from the prompts directory<idx>.json from the verdicts directoryduplicate verdictsdominant_skill_id per cluster (most-voted-dominant → has-evals → most lines → alphabetical)overlapping_pairs from overlapping verdictsduplicates.json--keep-intermediates if you want them preserved.jq -e '.schema_version == "1.0"' "$OUTPUT_PATH" > /dev/nullSanity-check: every skill_id mentioned in clusters[].skill_ids should exist in the source discovery.json.
duplicates-verdicts/<idx>.json; run finalize to test clustering / severity.