A configurable linter for agent skills, plugins, and AI coding assistant context
Project description
skillsawLint your skills before they cut someone. A configurable linter, doc generator, and CI companion for agentskills.io skills, Claude Code plugins, and plugin marketplaces.
|
Features
- ๐ Context-Aware โ Automatically detects agentskills repos, single plugins, and marketplaces and enables the right rules
- ๐ Rule-Based โ Enable/disable individual rules with configurable severity levels
- ๐ Doc Generation โ Generate HTML or Markdown documentation for your plugins and skills with
skillsaw docs - ๐ Extensible โ Load custom rules from Python files
- โ Comprehensive โ Validates skill format, plugin structure, metadata, command format, and cross-file consistency
- ๐ค CI-Ready โ GitHub Action posts inline PR comments with automatic deduplication and thread resolution
- ๐ณ Containerized โ Run via Docker for consistent, isolated linting
- โก Fast โ Efficient validation with clear, actionable output
Table of Contents
- Features
- Quick Start
- Installation
- Repository Types
- Configuration
- Builtin Rules
- Custom Rules
- Documentation Generation
- Exit Codes
- Example Output
- Migrating from claudelint
- Development
- Contributing
- License
- See Also
- Support
Quick Start
# Lint current directory (no install required)
uvx skillsaw
# Lint specific directory
skillsaw /path/to/skills
# Verbose output
skillsaw -v
# Strict mode (warnings as errors)
skillsaw --strict
# Generate default config
skillsaw --init
# List all available rules
skillsaw --list-rules
# Generate documentation
skillsaw docs
Installation
Via uvx (easiest โ no install required)
uvx skillsaw
uvx skillsaw /path/to/skills
Via pip
pip install skillsaw
From source
git clone https://github.com/stbenjam/skillsaw.git
cd skillsaw
pip install -e .
Using Docker
docker pull ghcr.io/stbenjam/skillsaw:latest
docker run -v $(pwd):/workspace ghcr.io/stbenjam/skillsaw
GitHub Action
The built-in GitHub Action installs skillsaw, runs it, and posts violations as inline PR comments with automatic deduplication. Fixed violations have their comment threads resolved.
name: Lint
on: [pull_request]
permissions:
contents: read
pull-requests: write
jobs:
skillsaw:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: stbenjam/skillsaw@v0
with:
strict: true
Inputs
| Input | Description | Default |
|---|---|---|
path |
Path to lint | . |
version |
Specific skillsaw version to install | latest |
strict |
Treat warnings as errors | false |
verbose |
Include info-level violations | false |
token |
GitHub token for posting PR comments | ${{ github.token }} |
Outputs
| Output | Description |
|---|---|
exit-code |
skillsaw exit code (0=pass, 1=errors, 2=strict+warnings) |
errors |
Number of errors found |
warnings |
Number of warnings found |
report |
Full JSON report |
PR comment behavior
- Each violation gets its own inline comment on the relevant line or file
- Comments are deduplicated across re-runs using content fingerprinting
- When a violation is fixed, its comment thread is automatically resolved
- Comments with human replies are preserved
Permissions:
contents: readis required for checkout.pull-requests: writeis required for posting comments.
Repository Types
skillsaw automatically detects your repository structure:
agentskills.io Skills
Standalone skill repositories following the agentskills.io specification:
my-skill/
โโโ SKILL.md # Required: metadata + instructions
โโโ scripts/ # Optional: executable code
โโโ references/ # Optional: documentation
โโโ assets/ # Optional: templates, resources
โโโ evals/ # Optional: evaluation tests
โ โโโ evals.json
โโโ <any-dir>/ # Arbitrary directories allowed per spec
Skill collections (multiple skills in subdirectories) are also supported:
skills-repo/
โโโ skill-one/
โ โโโ SKILL.md
โโโ skill-two/
โโโ SKILL.md
Standard discovery paths (.claude/skills/, .github/skills/, .agents/skills/) are checked automatically.
Single Plugin
my-plugin/
โโโ .claude-plugin/
โ โโโ plugin.json
โโโ commands/
โ โโโ my-command.md
โโโ skills/
โ โโโ my-skill/
โ โโโ SKILL.md
โโโ README.md
Marketplace (Multiple Plugins)
skillsaw supports multiple marketplace structures per the Claude Code specification:
Traditional Structure (plugins/ directory)
marketplace/
โโโ .claude-plugin/
โ โโโ marketplace.json
โโโ plugins/
โโโ plugin-one/
โ โโโ .claude-plugin/
โ โโโ commands/
โโโ plugin-two/
โโโ .claude-plugin/
โโโ commands/
Flat Structure (root-level plugin)
marketplace/
โโโ .claude-plugin/
โ โโโ marketplace.json # source: "./"
โโโ commands/
โ โโโ my-command.md
โโโ skills/
โโโ my-skill/
Custom Paths and Mixed Structures
Plugins from plugins/, custom paths, and remote sources can coexist in one marketplace. Only local sources are validated.
Configuration
Generate a default .skillsaw.yaml in your repository root:
skillsaw --init
This creates a config file with all builtin rules, their defaults, and
descriptions. Edit it to enable, disable, or customize rules for your project.
See .skillsaw.yaml.example for a complete example.
Builtin Rules
agentskills.io
These rules validate skills against the agentskills.io specification. They auto-enable for agentskills repos, single plugins, and marketplaces whenever skills are detected.
| Rule ID | Description | Default Severity |
|---|---|---|
agentskill-valid |
SKILL.md must have valid frontmatter with name and description | error (auto) |
agentskill-name |
Skill name must be lowercase with hyphens and match directory name | error (auto) |
agentskill-description |
Skill description should be meaningful and within length limits | warning (auto) |
agentskill-structure |
Skill directories should only contain recognized subdirectories (stricter than spec) | warning (disabled) |
agentskill-evals |
Validate evals/evals.json format when present | error (auto) |
agentskill-evals-required |
Require evals/evals.json for each skill (opt-in) | error (disabled) |
agentskill-structure parameters:
| Parameter | Description | Default |
|---|---|---|
allowed_dirs |
Directory names allowed in the skill root | ["assets", "evals", "references", "scripts"] |
Plugin Structure
| Rule ID | Description | Default Severity |
|---|---|---|
plugin-json-required |
Plugin must have .claude-plugin/plugin.json | error (auto) |
plugin-json-valid |
Plugin.json must be valid JSON with required fields | error (auto) |
plugin-naming |
Plugin names should use kebab-case | warning (auto) |
plugin-readme |
Plugin should have a README.md file | warning (auto) |
plugin-json-valid parameters:
| Parameter | Description | Default |
|---|---|---|
recommended-fields |
Fields that trigger a warning if missing from plugin.json | ["description", "version", "author"] |
Command Format
| Rule ID | Description | Default Severity |
|---|---|---|
command-naming |
Command files should use kebab-case naming | warning |
command-frontmatter |
Command files must have valid frontmatter with description | error |
command-sections |
Command files should have Name, Synopsis, Description, and Implementation sections | warning |
command-name-format |
Command Name section should be 'plugin-name:command-name' | warning |
Marketplace
| Rule ID | Description | Default Severity |
|---|---|---|
marketplace-json-valid |
Marketplace.json must be valid JSON with required fields | error (auto) |
marketplace-registration |
Plugins must be registered in marketplace.json | error (auto) |
Skills, Agents, Hooks
| Rule ID | Description | Default Severity |
|---|---|---|
skill-frontmatter |
SKILL.md files should have frontmatter with name and description | warning |
agent-frontmatter |
Agent files must have valid frontmatter with name and description | error |
hooks-json-valid |
hooks.json must be valid JSON with proper hook configuration structure | error |
MCP (Model Context Protocol)
| Rule ID | Description | Default Severity |
|---|---|---|
mcp-valid-json |
MCP configuration must be valid JSON with proper mcpServers structure | error |
mcp-prohibited |
Plugins should not enable non-allowlisted MCP servers | error (disabled) |
mcp-prohibited parameters:
| Parameter | Description | Default |
|---|---|---|
allowlist |
MCP server names that are permitted | [] |
Rules Directory
| Rule ID | Description | Default Severity |
|---|---|---|
rules-valid |
.claude/rules/ files must be markdown with valid optional paths frontmatter | error (auto) |
Openclaw
Validates metadata.openclaw in SKILL.md frontmatter against the openclaw spec. Only fires when metadata.openclaw is present.
| Rule ID | Description | Default Severity |
|---|---|---|
openclaw-metadata |
Validate metadata.openclaw fields against the openclaw spec | warning (auto) |
Custom Rules
Create custom validation rules by extending the Rule base class:
from pathlib import Path
from typing import List
from skillsaw import Rule, RuleViolation, Severity, RepositoryContext
class NoTodoCommentsRule(Rule):
@property
def rule_id(self) -> str:
return "no-todo-comments"
@property
def description(self) -> str:
return "Command files should not contain TODO comments"
def default_severity(self) -> Severity:
return Severity.WARNING
def check(self, context: RepositoryContext) -> List[RuleViolation]:
violations = []
for plugin_path in context.plugins:
commands_dir = plugin_path / "commands"
if not commands_dir.exists():
continue
for cmd_file in commands_dir.glob("*.md"):
content = cmd_file.read_text()
if "TODO" in content:
violations.append(
self.violation("Found TODO comment", file_path=cmd_file)
)
return violations
Then reference it in .skillsaw.yaml:
custom-rules:
- ./my_custom_rules.py
rules:
no-todo-comments:
enabled: true
severity: warning
Documentation Generation
skillsaw can generate documentation for your plugins, skills, and marketplaces:
# Generate HTML docs (default)
skillsaw docs
# Generate Markdown
skillsaw docs --format markdown
# Write to a specific file
skillsaw docs --format markdown -o docs/README.md
# Write to a directory
skillsaw docs -o my-docs/
# Custom title
skillsaw docs --title "My Plugin Docs"
The generated documentation includes plugin metadata, command descriptions, skill summaries, and configuration details extracted from your repository.
Exit Codes
0- Success (no errors, or warnings only in non-strict mode)1- Failure (errors found, or warnings in strict mode)
Example Output
Linting: /path/to/skills-repo
Errors:
โ ERROR [skills/my-skill/SKILL.md]: Name 'My Skill' must contain only lowercase letters, numbers, and hyphens
โ ERROR [plugins/git/.claude-plugin/plugin.json]: Missing plugin.json
Warnings:
โ WARNING [skills/helper/SKILL.md]: Description exceeds 1024 characters (1087)
โ WARNING [plugins/utils]: Missing README.md (recommended)
Summary:
Errors: 2
Warnings: 2
Migrating from claudelint
This project was renamed from claudelint to skillsaw. To migrate:
- Update your package:
pip install skillsaw(instead ofpip install claudelint) - Rename
.claudelint.yamlto.skillsaw.yaml(the old name is still discovered as a fallback) - Update CLI usage:
skillsaw(instead ofclaudelint) - Update imports in custom rules:
from skillsaw import ...(the oldfrom claudelint import ...still works)
The claudelint command still works as a shim but prints a deprecation warning.
Removed rules
The following rules from claudelint have been removed in skillsaw:
| Rule ID | Reason |
|---|---|
commands-dir-required |
Claude Code now treats skills/ and commands/ as the same mechanism; requiring a commands/ directory is no longer meaningful |
commands-exist |
Same as above โ plugins don't need to have commands |
If your .skillsaw.yaml references these rule IDs, skillsaw will emit a warning about the unknown rule.
Development
# Run tests
pytest tests/ -v
# Format code
black src/ tests/
# Build Docker image
docker build -t skillsaw .
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
Apache 2.0 - See LICENSE for details.
See Also
- agentskills.io Specification
- Claude Code Documentation
- Claude Code Plugins Reference
- AI Helpers Marketplace - Example marketplace using skillsaw
Support
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 skillsaw-0.6.0.tar.gz.
File metadata
- Download URL: skillsaw-0.6.0.tar.gz
- Upload date:
- Size: 83.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48bae1cda78eb034df683f7cad03469540f99d9d521e50165c7f678bf024ac0a
|
|
| MD5 |
fbd9904047173ca02e0fa93f31780cdd
|
|
| BLAKE2b-256 |
f32bf3414387759ba5ac00932905eeed2ed1c8ff00a9ae573390a4fc4e91672f
|
Provenance
The following attestation bundles were made for skillsaw-0.6.0.tar.gz:
Publisher:
release.yml on stbenjam/skillsaw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skillsaw-0.6.0.tar.gz -
Subject digest:
48bae1cda78eb034df683f7cad03469540f99d9d521e50165c7f678bf024ac0a - Sigstore transparency entry: 1474980562
- Sigstore integration time:
-
Permalink:
stbenjam/skillsaw@e4ca2bfd18636ef23373b614827c4bf3d2f8610c -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/stbenjam
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e4ca2bfd18636ef23373b614827c4bf3d2f8610c -
Trigger Event:
release
-
Statement type:
File details
Details for the file skillsaw-0.6.0-py3-none-any.whl.
File metadata
- Download URL: skillsaw-0.6.0-py3-none-any.whl
- Upload date:
- Size: 65.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
684ec245df22eccdb8775aa25c017a4355244b0f7ff35f811b241ff8ea5e55ce
|
|
| MD5 |
de0215abc564ed1232d49794cecbf1ff
|
|
| BLAKE2b-256 |
2e8621f2ec7ebf44ac7cee693e95ec94733138f8059942eb445c5b4e851a06a7
|
Provenance
The following attestation bundles were made for skillsaw-0.6.0-py3-none-any.whl:
Publisher:
release.yml on stbenjam/skillsaw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skillsaw-0.6.0-py3-none-any.whl -
Subject digest:
684ec245df22eccdb8775aa25c017a4355244b0f7ff35f811b241ff8ea5e55ce - Sigstore transparency entry: 1474980614
- Sigstore integration time:
-
Permalink:
stbenjam/skillsaw@e4ca2bfd18636ef23373b614827c4bf3d2f8610c -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/stbenjam
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e4ca2bfd18636ef23373b614827c4bf3d2f8610c -
Trigger Event:
release
-
Statement type: