Static analysis linter for Claude Code plugins, skills, and agents
Project description
skilllint
Static analysis linter for AI agent plugins, skills, and agents — for Claude Code, Cursor, Codex, and any agentskills.io-compatible platform.
What it does
skilllint validates the structure and content of AI agent files: plugins, skills, agents, and commands. It catches broken references, missing frontmatter, oversized skills, invalid hook configurations, and more — before they cause silent failures at runtime.
$ skilllint check plugins/my-plugin
plugins/my-plugin/skills/my-skill/SKILL.md
SK006 Token count 14823 exceeds recommended limit of 8192
plugins/my-plugin/agents/my-agent.md
NR001 Namespace reference 'other-plugin:some-skill' — plugin directory not found
2 errors in 2 files
Screenshots
Validation output with errors and warnings
All available rules
Rule detail
Installation
pip install skilllint
Or with uv:
uv add skilllint # add to a project
uv tool install skilllint # install as a global tool
Requires Python 3.11–3.14.
Quick start
# Validate a plugin directory
skilllint check plugins/my-plugin
# Validate a single skill file
skilllint check plugins/my-plugin/skills/my-skill/SKILL.md
# Validate everything and show a summary
skilllint check --show-summary plugins/
# Auto-fix issues where possible
skilllint check --fix plugins/my-plugin
# Count tokens in any markdown file
skilllint check --tokens-only .claude/CLAUDE.md
Exit codes: 0 = all checks passed · 1 = validation errors · 2 = usage error
GitHub Action
Use bitflight-devops/skilllint as a GitHub Action to validate skills, plugins, and agents in any repository:
- uses: bitflight-devops/skilllint@v1.7.0
with:
paths: "plugins/" # paths to validate (default: ".")
platform: "claude-code" # restrict to one platform (optional)
show-summary: "true" # show summary panel (default: true)
Full input reference
| Input | Description | Default |
|---|---|---|
paths |
Space-separated paths to validate | . |
platform |
Platform adapter: claude-code, cursor, codex |
(all) |
fix |
Auto-fix issues where possible | false |
check-only |
Validate only, do not auto-fix | false |
verbose |
Show detailed output including info messages | false |
no-color |
Disable color output | true |
tokens-only |
Output only the integer token count | false |
show-progress |
Show per-file PASSED/FAILED status | false |
show-summary |
Show summary panel at the end | true |
filter |
Glob pattern to restrict files within a directory | (none) |
filter-type |
File type filter: skills, agents, commands |
(all) |
version |
skilllint version to install (latest or 1.2.3) |
latest |
python-version |
Python version to use | 3.12 |
Outputs
| Output | Description |
|---|---|
result |
passed when exit code is 0; failed for any non-zero exit code |
exit-code |
Raw exit code: 0 = pass · 1 = errors · 2 = usage error |
Example: fail the CI on validation errors
name: Validate skills
on: [push, pull_request]
jobs:
skilllint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint skills and plugins
uses: bitflight-devops/skilllint@v1.7.0
with:
paths: "plugins/ .claude/"
platform: "claude-code"
show-summary: "true"
verbose: "false"
Example: report results without blocking
- name: Lint skills and plugins
id: lint
uses: bitflight-devops/skilllint@v1.7.0
with:
paths: "plugins/"
continue-on-error: true
- name: Print result
run: echo "skilllint result=${{ steps.lint.outputs.result }}"
Pre-commit hook
Add to .pre-commit-config.yaml:
repos:
- repo: https://github.com/bitflight-devops/skilllint
rev: v1.7.0
hooks:
- id: skilllint
Platform support
skilllint ships with adapters for three platforms and supports third-party adapters via Python entry points:
| Platform | Adapter ID | Bundled |
|---|---|---|
| Claude Code | claude-code |
✓ |
| Cursor | cursor |
✓ |
| OpenAI Codex | codex |
✓ |
| OpenCode, Gemini, and others | — | via entry points |
Restrict validation to one platform:
skilllint check --platform claude-code plugins/my-plugin
What gets validated
| Code | Category | Description |
|---|---|---|
| FM001–FM010 | Frontmatter | Required fields, valid values, schema compliance |
| SK001–SK009 | Skill | Description quality, token limits, complexity, internal links |
| AS001–AS009 | AgentSkills | Cross-platform open standard compliance |
| LK001–LK002 | Links | Markdown link validity and broken reference detection |
| PD001–PD003 | Progressive disclosure | Directory structure for references/, examples/, scripts/ |
| PL001–PL006 | Plugin | Structure, manifest correctness, marketplace layout, subprocess safety |
| HK001–HK005 | Hook | Script existence, configuration validity |
| NR001–NR002 | Namespace refs | Cross-plugin skill/agent/command references |
| SL001 | Symlinks | Symlink hygiene within plugin directory |
| TC001 | Token count | Token count reporting and threshold enforcement |
| PR001–PR005 | Plugin registration | Capability registration completeness and correctness in plugin.json |
| PA001 | Plugin agent | Plugin-packaged agents: hooks / mcpServers / permissionMode unsupported per Anthropic (ignored at load; cite sub-agents doc) |
| CU001–CU002 | Cursor | Cursor .mdc frontmatter required fields and enum values |
| CX001–CX002 | Codex | Codex AGENTS.md content non-empty and header presence |
CLI reference
Usage: skilllint [OPTIONS] COMMAND [ARGS]...
Commands:
check Validate Claude Code plugins, skills, agents, and commands.
docs Fetch, query, and verify cached vendor documentation.
rule Show documentation for a validation rule.
rules List all available validation rules.
Options:
--help Show this message and exit.
check
Usage: skilllint check [OPTIONS] [PATHS]...
Arguments:
paths Paths to validate
Options:
--check Validate only, don't auto-fix
--fix Auto-fix issues where possible
--verbose, -v Show detailed output
--no-color Disable color
--tokens-only Output token count only
--show-progress Show per-file status
--show-summary Show summary panel
--filter TEXT Glob pattern to match files within a directory
--filter-type TEXT Filter type (skills | agents | commands)
--platform TEXT Platform adapter
--include-gitignore Scan files excluded by .gitignore (default: skip them)
--record PATH Record terminal output to SVG or HTML file
--help Show this message and exit
rules
Usage: skilllint rules [OPTIONS]
Options:
--platform, -p TEXT Filter rules by platform
--category, -c TEXT Filter rules by category
--severity, -s TEXT Filter rules by severity (error, warning, info)
--record PATH Record terminal output to SVG or HTML file
--help Show this message and exit
rule
Usage: skilllint rule [OPTIONS] RULE_ID
Arguments:
rule_id Rule identifier (e.g., "SK001", "FM002", "AS001") [required]
Options:
--record PATH Record terminal output to SVG or HTML file
--help Show this message and exit
docs
Cache and query vendor documentation pages for offline use.
Usage: skilllint docs [OPTIONS] COMMAND [ARGS]...
Commands:
fetch Fetch a documentation page or return a cached copy.
latest Find the most recent cached file for a page name.
sections Print a table of sections in a cached markdown file.
section Extract the text of a named section from a cached markdown file.
verify Verify a cached file against its .meta.json integrity sidecar.
docs fetch
Usage: skilllint docs fetch [OPTIONS] URL
Arguments:
url Documentation URL to fetch or serve from cache.
Cache Options:
--ttl FLOAT Cache time-to-live in hours before a refresh is attempted. [default: 4.0]
--force Skip the freshness check and always attempt a network fetch.
Options:
--help Show this message and exit.
Prints the cached file path to stdout. Status messages go to stderr. Exits 1 when no cache exists and the network is unavailable.
docs latest
Usage: skilllint docs latest [OPTIONS] PAGE_NAME
Arguments:
page_name Filesystem-safe page name (e.g. 'claude-code--settings').
Options:
--help Show this message and exit.
Prints the file path to stdout. Exits 1 when no cached file exists for that page name.
docs sections
Usage: skilllint docs sections [OPTIONS] FILE_PATH
Arguments:
file_path Path to the cached markdown file to index.
Options:
--help Show this message and exit.
Prints a table of headings with their line ranges to stdout.
docs section
Usage: skilllint docs section [OPTIONS] FILE_PATH HEADING
Arguments:
file_path Path to the cached markdown file.
heading Heading text or markdown anchor slug to locate.
Options:
--help Show this message and exit.
Prints the full text of the matching section to stdout. Exits 1 when the heading is not found.
Heading matching is case-insensitive and accepts two forms:
- Heading text:
"Hook input and output" - Markdown anchor slug:
"hook-input-and-output"
Leading # characters are stripped before comparison.
docs verify
Usage: skilllint docs verify [OPTIONS] FILE_PATH
Arguments:
file_path Path to the cached markdown file to verify.
Options:
--help Show this message and exit.
Exits 0 when the file is intact. Exits 1 when the file has been modified or when no sidecar exists.
All four command names are aliases for the same tool:
skilllint # primary
agentlint # alias
pluginlint # alias
skillint # alias
Vendor documentation cache
skilllint docs provides an offline-first cache for vendor documentation pages. Pages are
fetched once and stored locally; subsequent calls within the TTL window are served from
disk without a network request. When the TTL has expired but the network is unavailable,
the stale copy is served automatically.
Cached files are written to .claude/vendor/sources/ with filenames in the format
{page-name}-{YYYY-MM-DD-HHMM}.md. Each file is accompanied by a .meta.json integrity
sidecar that records the SHA-256 digest, byte count, source URL, and fetch timestamp.
# Cache a documentation page (default TTL: 4 hours)
skilllint docs fetch https://docs.anthropic.com/en/docs/claude-code/settings.md
# Force a network refresh regardless of TTL
skilllint docs fetch https://docs.anthropic.com/en/docs/claude-code/settings.md --force
# Find the most recently cached copy of a page
skilllint docs latest claude-code--settings
# List all sections with line ranges
skilllint docs sections .claude/vendor/sources/claude-code--settings-2025-01-01-1200.md
# Extract a section by heading text or markdown anchor slug
skilllint docs section .claude/vendor/sources/claude-code--settings-2025-01-01-1200.md "Hook input and output"
skilllint docs section .claude/vendor/sources/claude-code--settings-2025-01-01-1200.md "hook-input-and-output"
# Verify a cached file against its sidecar
skilllint docs verify .claude/vendor/sources/claude-code--settings-2025-01-01-1200.md
Section extraction uses marko for AST-based
markdown parsing, so # characters inside fenced code blocks are never mistaken for
headings.
If skilllint is not installed, use uvx to run it without a permanent install:
uvx skilllint docs fetch https://docs.anthropic.com/en/docs/claude-code/settings.md
scripts/fetch_doc_source.py is a PEP 723 standalone script that exposes the same
commands via uv run --script. It is intended for contributors working directly on
the skilllint source tree (where [tool.uv.sources] points the dependency at the
local package), not for end users.
Suppressing warnings
Use a .skilllint.json file to suppress specific rule codes for a directory tree. Place the file at any level — skilllint walks up from each scanned file and uses the nearest config it finds.
{
"ignore": {
"": ["AS008"],
"skills/legacy": ["LK002", "SK006"]
}
}
Key format:
| Key | Scope |
|---|---|
"" (empty string) |
All files under this .skilllint.json |
"skills/legacy" |
Files whose path (relative to the config file) starts with that prefix |
Plugin-level suppression (inside a .claude-plugin/ plugin):
Place validator.json inside .claude-plugin/:
{
"ignore": {
"": ["PA001"],
"agents/generated": ["FM004", "FM007"]
}
}
The same key format applies. Plugin-level config takes priority over a .skilllint.json in a parent directory.
See docs/ignore-config.md for the full reference.
Third-party adapters
Register a custom platform adapter via Python entry points in your pyproject.toml:
[project.entry-points."skilllint.adapters"]
my-platform = "my_package.adapter:MyPlatformAdapter"
Your adapter must implement the AdapterProtocol interface from skilllint.adapters.protocol.
Links
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file skilllint-1.8.0.tar.gz.
File metadata
- Download URL: skilllint-1.8.0.tar.gz
- Upload date:
- Size: 318.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7f3de069b81c588011259c768b4e285c5cf557c0c8751441ecfef77ee565924
|
|
| MD5 |
60142f6ee3847f8f151056051e656845
|
|
| BLAKE2b-256 |
45936d6e0d8c4c09cbcccd1fc75401ad917418d1e03028c3376ab3fea555e82f
|
File details
Details for the file skilllint-1.8.0-py3-none-any.whl.
File metadata
- Download URL: skilllint-1.8.0-py3-none-any.whl
- Upload date:
- Size: 181.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5357ff8c5d9db45bf0fd0649a53b2c99607c93c96aa17114a3b05b626d4415c
|
|
| MD5 |
2fca9f85adb32c852df7490ba6cb54ed
|
|
| BLAKE2b-256 |
b7488dcac26eacdac9bfe887004b207d54240ad592714cd7f218ddaf46c9a8e8
|