Skip to content

fix(skill-lint): check that every skill package is registered - #31

Open
harrymove-ctrl wants to merge 2 commits into
mainfrom
fix/skill-lint-registration
Open

harrymove-ctrl wants to merge 2 commits into
mainfrom
fix/skill-lint-registration

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Contributor

Why

A skill directory is only half a skill. Adding skills/<name>/ without registering it leaves an orphan package in the docs tree and renders the skill degraded on the site — and nothing caught it, because every missing registry entry has a silent fallback.

Skills are filesystem-discovered (lib/skills.ts:29), so an unregistered skill still renders. CATEGORY_MAP has no entry, so it falls to "other". SKILL_PURPOSE has no entry, so skillPurpose() falls back to the first quoted trigger phrase scraped off the description. Neither build nor skill-lint says a word.

This is not hypothetical. Measured against the three open skill-adding PRs at the time of writing:

PR New skills Registration points missing
#21 visualize 4 of 4
#28 write-cmk-skill 0 — caught in review, fixed by hand
#30 capability-map, trace-audit, elicit 10 of 12

#28's were found by a human reading the diff. That is the part this check replaces.

What it does

Four registration points per skill directory:

  1. docs/ai/skills/<name>.md exists
  2. the name is rostered in docs/ai/skills/README.md
  3. a CATEGORY_MAP entry in lib/skill-types.ts
  4. a SKILL_PURPOSE entry in lib/skill-types.ts

Registry keys are written both quoted ("delivery-ship") and bare (sync), so a grep for either form alone misses half of them. scripts/skill-registry-keys.py parses the two object literals instead.

Verification

Run against each branch, with the check wired in:

Both directions matter: a check that only ever passes proves nothing.

The one allowlist entry

enclave shipped without a docs/ai/skills/ page long before this check existed. It is allowlisted with a comment rather than silently exempted — closing that gap is its own change. The file's existing note applies: a new entry there must be a deliberate, reviewed decision, not a way to silence a fresh violation.

A skill directory is only half a skill. Adding skills/<name>/ without
registering it leaves an orphan package in the docs tree and renders the
skill degraded on the site, and nothing caught it: skills are
filesystem-discovered, so every missing registry entry has a silent
fallback. A CATEGORY_MAP miss falls to "other"; a SKILL_PURPOSE miss falls
back to a trigger phrase scraped from the description.

Checks four registration points per skill directory -- the docs page, the
docs README roster, CATEGORY_MAP, and SKILL_PURPOSE. Registry keys are
written both quoted and bare in lib/skill-types.ts, so they are parsed out
rather than grepped.

enclave is allowlisted: it shipped without a docs page long before this
check and closing that gap is its own change.
The registration check reads lib/skill-types.ts, docs/ai/skills/, and
scripts/skill-registry-keys.py, none of which the workflow watched. It
caught a skill added without registration, because that touches skills/.
It would not have caught registration taken away from a skill that
already had it -- dropping a CATEGORY_MAP entry or deleting a docs page
leaves skills/ untouched, so the lint never ran.
@harrymove-ctrl
harrymove-ctrl force-pushed the fix/skill-lint-registration branch from 832b921 to bc64cd3 Compare September 18, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants