The description is the only signal an agent sees at discovery time, so
overlapping descriptions cause misrouting. Nothing in CI checked for that.
- tools/lint-descriptions.py enforces name==folder, description <=1024
chars, terminal punctuation (a truncation canary), a trigger clause, a
negative trigger, and a 500-line body cap. Pre-existing failures are
grandfathered in tools/lint-baseline.json so this blocks new debt only;
the baseline may shrink and never grow.
- tools/detect-collisions.py scores every description pair by TF-IDF
cosine and ratchets the count of unreviewed near-duplicates. It strips
negative-trigger clauses before vectorizing: those name the sibling
skill on purpose, so scoring them would make correct disambiguation
raise a pair's similarity.
- wire both into validate-skills.yml, along with agentskills conformance,
an index.json freshness check, and a guard that fails the build if a
regex frontmatter parser is reintroduced.
- broaden the path filters from tools/validate-skill.py to tools/**, as
noted when #105 merged.
All five gates verified to fail on deliberately broken input.
index.json shipped 604 of 817 descriptions truncated to their first line.
The cause was the inline regex parser in update-index.yml: it reconstructed
multi-line descriptions only for the YAML block-scalar styles ('>' and '|')
and silently dropped continuation lines for every other style.
A census of the corpus explains the blast radius:
block scalar (description: >-) 43
single-quoted multiline 278
plain unquoted multiline 496
single-line 0
So 774 of 817 skills (94.7%) used a style the parser mishandled. Commit
d56fc0a7 had fixed only the 43 block-scalar files, and CONTRIBUTING.md
recommends that one working style, which is why it stayed hidden.
- add tools/skill_frontmatter.py, the single PyYAML-backed loader
- add tools/generate-index.py so generation is testable outside CI, with
a --check mode for use as a gate
- delete the hand-rolled parsers from validate-skill.py (98 lines) and
validate-agentskills.py, routing both through the shared loader
- implement the reserved-word check that agentskills-skill.schema.json
names validate-agentskills.py as the enforcement point for
Verified by a differential harness against yaml.safe_load ground truth:
index-vs-source mismatches 606 -> 0.
The generator's `^description:\s*(.+)$` regex captured the block-scalar
indicator (">-") instead of the wrapped text, corrupting 43 descriptions in
index.json. Parse `>`/`|` block scalars properly and regenerate (0 broken).
Also refresh the count-update comment examples 754 -> 817.
Address PR review threads: valid YAML subdomain example, separate
D3FEND list items, NIST CSF ID convention, document tools/validate-skill.py,
and fix Quick Reference backticks.
Add tools/validate-skill.py and the workflow file to the push/pull_request
path filters so edits to the validator or workflow re-run validation, and
add workflow_dispatch for manual runs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Issues found in review:
1. tools/validate-skill.py: parse_frontmatter operated on the stripped line, so
an indented nested `name:` (under framework-mapping lists, e.g.
`name: 'Create Fake Materials: Fake Website'`) clobbered the skill's
top-level `name`. That produced 94 spurious "invalid kebab-case name"
failures out of 762. Now indented (non-list) key lines are ignored, so only
top-level keys define frontmatter fields. Result: 762/762 pass.
2. Two divergent validators: the CI workflow had its own weaker inline parser
(no subdomain/tag/description checks) requiring a different field set than
tools/validate-skill.py. CI now delegates to tools/validate-skill.py --all
(single source of truth); REQUIRED_FIELDS aligned to include
version/author/license. The duplicate-name and stats steps are unchanged.
3. README: added an explicit authorized-&-lawful-use disclaimer next to the
existing "not affiliated with Anthropic" note, since the library ships
offensive/dual-use techniques.
No skill content changed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- plugin.json was stuck at version 1.0.0 and count 753 — this is the file the
installer reads, so installs showed 1.0 everywhere. Bumped to 1.2.0 / 762.
- Update skill count to 762 across README (badge + 6 mentions), marketplace.json,
and plugin.json (754/753 -> 762 after merging PRs #70/#71/#81)
- update-index.yml: now auto-syncs the skill count into README.md,
marketplace.json, and plugin.json on every skills/ change (no more manual drift)
- sync-marketplace-version.yml: release now bumps plugin.json too (not just
marketplace.json) and pushes to main, so plugin version tracks the release tag