Skip to main content

skill-lint

CI PyPI Python versions License: MIT

A Claude Code skill lives or dies by one field: its description. Claude reads the name + description of every skill at session start and decides from that text alone whether your skill ever fires. A typo'd frontmatter key is ignored silently. Malformed YAML loads the skill with empty metadata — it will never auto-trigger and nothing tells you. A description that says what but never when under-triggers. And every character of every description is context you pay for at every session.

skill-lint is the linter for that one field and everything around it: one command, zero dependencies, tells you which skills are dead, which are silently broken, and what your skills cost at boot.

  • Dead skills — malformed frontmatter, no description and nothing to fall back on: skills that can never trigger.
  • Silent typos — descripton: instead of description: is ignored without a word; skill-lint catches it and suggests the fix.
  • Under-triggering descriptions — too short, no usage cue, or truncated past the 1,536-character listing cap so Claude never sees the tail.
  • Boot cost — chars and estimated tokens of names + descriptions loaded every session, per skill and total; manual-only skills (disable-model-invocation: true) correctly counted at zero.

Install

pipx install skill-lint

or

pip install skill-lint

or straight from source:

pipx install git+https://github.com/trinity-organism/skill-lint

Python >= 3.9. Zero dependencies — standard library only.

Usage

skill-lint                # lint $CLAUDE_CONFIG_DIR/skills, falling back to ~/.claude/skills
skill-lint --dir DIR      # lint any skills directory (a project's .claude/skills, a plugin's skills/)
skill-lint --json         # machine-readable output

Exit codes: 0 clean (or no skills found), 1 at least one finding, 2 unreadable directory — so it drops straight into CI or a pre-commit hook.

Example

Real output on a demo skills directory:

$ skill-lint --dir skills
skill-lint — SKILL.md quality + boot cost
skills dir: skills

ok    deploy-staging  170 chars (~42 tok) at boot
WARN  meeting-notes   65 chars (~16 tok) at boot
      - WARN [no-when-cue]: description says what the skill does but never when to use it (no 'use/when/for/trigger...' cue): skills without usage context under-trigger
WARN  pdf-tools       47 chars (~11 tok) at boot
      - WARN [unknown-key]: frontmatter key 'descripton' is not a documented field and is ignored silently (did you mean 'description'?)
      - WARN [no-description]: no description in frontmatter: triggering relies on the first body paragraph, which was not written for matching
ERROR scratch         20 chars (~5 tok) at boot
      - ERROR [broken-frontmatter]: unparseable line 4 in frontmatter: malformed YAML means empty metadata, so the skill never auto-triggers

verdict — skills: 4 · errors: 1 · warnings: 3 · boot cost: 302 chars (~75 tokens) of names+descriptions every session
$ echo $?
1

And when there is nothing to lint:

$ skill-lint --dir /some/empty/dir
skill-lint: no skills found in /some/empty/dir
Nothing to lint. If your skills live elsewhere, point at them with --dir DIR or $CLAUDE_CONFIG_DIR.

Rules

Every rule traces to documented Claude Code behavior, not taste.

Rule Severity Why it matters
broken-frontmatter error Malformed YAML loads the skill with empty metadata: it never auto-triggers.
undiscoverable error No description and an empty body: nothing for Claude to match, ever.
no-description warning Matching falls back to the first body paragraph, which wasn't written for matching.
no-frontmatter warning Same fallback; the skill also loses every other frontmatter feature.
desc-too-short warning A handful of characters gives Claude nothing to match against.
no-when-cue warning Says what but never when: the documented under-triggering failure mode.
desc-truncated warning description + when_to_use past 1,536 chars is cut in the listing — the tail is invisible.
unknown-key warning Unknown frontmatter fields are ignored silently; usually a typo (did-you-mean included).
duplicate-key warning Only one value survives a duplicated key.
empty-body warning The skill triggers and delivers nothing.
no-skill-md warning A directory in the skills root with no SKILL.md is dead weight, never loaded.

Folded and literal YAML blocks (description: > / |) are parsed correctly — the classic case where naive parsers read an empty description and report garbage.

Why lint descriptions at all?

Claude Code loads skill names and descriptions into a context budget (about 1% of the model's context window). When it overflows, descriptions get dropped. Skills that never trigger still bill you that budget at every session — a config that only ever grows, with nothing pruning it. Lint it, fix the dead weight, keep the budget for skills that fire.

Auditing the rest of your config (hooks, duplicate levers)? That's this tool's sibling: bridle-audit.

Development

pip install -e ".[dev]"
pytest

The test suite fabricates synthetic skills in temp directories — it never reads your real ~/.claude.

License

MIT

Metadata

Release files for claude-skill-lint 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for claude-skill-lint 0.1.0
File Size Uploaded
claude_skill_lint-0.1.0.tar.gz 11.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for claude-skill-lint 0.1.0
File Interpreter ABI Platform
claude_skill_lint-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 22.0 kB

Release files / claude_skill_lint-0.1.0.tar.gz

Download URL claude_skill_lint-0.1.0.tar.gz
Size 11.9 kB
Tags Source
SHA-256 checksum
How to use checksums
47433c024aa4dc34b8f9a06e22c669708a6e7a9cd8b78fd31f098771835fc965
BLAKE2b-256 checksum
How to use checksums
4c4acacb449d68edc3487cee49e699d7c50067a55e6e6fe519737307461ede46
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / claude_skill_lint-0.1.0-py3-none-any.whl

Download URL claude_skill_lint-0.1.0-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a87fa9be838b9d71cf82d4ea2c24c8678641d6e8ba27503e3fba71463de8cc72
BLAKE2b-256 checksum
How to use checksums
abab4e6b1c0568d307df324958d7d7866c9927d78c5eaeef088f2cdf706c0b67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page