ESLint + Jest for agent-config files. skillcraft lints, syncs and scaffolds the fragmented ecosystem of SKILL.md, CLAUDE.md and AGENTS.md — one canonical source, many managed targets, drift detection in CI.
Agent-config files are copy-pasted, drift apart across tools, and silently fail to load.
skillcraftgives them the same lint/test/sync workflow that code already enjoys.
uv tool install skillcraft # or: pip install skillcraft
cd your-repo
skillcraft init --name my-skill # writes a canonical AGENTS.md + .skillcraft.toml
# ...edit AGENTS.md...
skillcraft sync # generates managed SKILL.md + CLAUDE.md
skillcraft lint # validates every agent-config file in the repoIn CI, lock it down:
skillcraft sync --check # exit 1 if SKILL.md/CLAUDE.md drifted from AGENTS.md
skillcraft lint --check # exit 1 on any ERROR; --format=github annotates the PR- One source of truth. Write
AGENTS.mdonce;skillcraft syncregeneratesSKILL.mdandCLAUDE.md. Edit a target by hand andsync --checkcatches the drift. - Lint that knows the formats. Kebab-case names, frontmatter presence, import cycles, token budgets, merge-conflict markers — see the rule table.
- PR annotations.
--format=githubemits::error file=…,line=…::…so findings render inline on pull requests. - Plugin-friendly. Add a rule or a format converter in one file, no core changes. See Contributing.
| Command | Purpose |
|---|---|
skillcraft lint [--check] [-f plain|json|github] |
Run the rule set over discovered config files; exit 1 on any ERROR. |
skillcraft sync [--check] [--diff] [--adopt <file>] |
Regenerate managed targets from AGENTS.md; detect or rewrite drift. |
skillcraft init [--name <name>] |
Scaffold a minimal AGENTS.md + .skillcraft.toml. |
skillcraft version |
Print the version. |
| ID | Scope | Rule | Severity |
|---|---|---|---|
| SC101 | SKILL | name is kebab-case, ≤64 chars |
error |
| SC102 | SKILL | in a skills/<name>/ folder, name matches the folder |
error |
| SC103 | SKILL | description present, ≤1024 chars |
error |
| SC104 | SKILL | body ≈ <5000 tokens | warn |
| SC201 | CLAUDE | @path imports resolve, no cycles, ≤4 hops |
error/warn |
| SC202 | CLAUDE | line count <200 (warn), <500 (error) | warn/error |
| SC301 | ALL | required frontmatter present iff the format requires it | error |
| SC302 | ALL | no merge-conflict markers in the body | error |
Rule IDs are stable and never renumbered — SC1xx = SKILL, SC2xx = CLAUDE, SC3xx = universal, SC4xx = .cursor (v0.2). Every spec'd rule not yet implemented is an open good-first-issue.
AGENTS.md is the canonical source — vendor-neutral, schema-less. Richer metadata (name, description, scope, license, …) rides in invisible HTML comments that every markdown consumer ignores but skillcraft reads:
<!-- skillcraft:meta {"name":"my-skill","description":"…"} -->
# my-skill
…Every format parses into a single ConfigDoc IR and renders back out. Same-format parse→render is lossless; an extra_frontmatter escape hatch guarantees no field is ever silently dropped. Managed targets carry a marker:
<!-- skillcraft:managed-source path=AGENTS.md sha=30b2058ede77 -->sync --check compares each managed target against a fresh render and fails CI on any difference. See ARCHITECTURE.md for the full model.
from skillcraft.plugins.api import Rule, Diagnostic
from skillcraft.plugins.registry import register_rule
@register_rule
class SkillNameLength(Rule):
id = "SC101"
formats = ("skill",)
severity = "error"
def check(self, doc):
if doc.meta.name and len(doc.meta.name) > 64:
yield Diagnostic(self.id, self.severity, "skill name >64 chars",
str(doc.meta.source_path))Ship it as a package with one entry-point — skillcraft lint discovers and runs it automatically:
[project.entry-points."skillcraft.rules"]
my_rules = "my_plugin.rules"Converters (new formats) use the identical shape under the skillcraft.converters group. Full guide: CONTRIBUTING.md.
skillcraft is its own first user. This repo's SKILL.md and CLAUDE.md are generated from AGENTS.md by skillcraft sync, and CI runs skillcraft lint --check + skillcraft sync --check on every push — if the project's own configs drift or violate a rule, the build fails.
- v0.1 — lint (8 rules, 3 formats) + sync + init + version +
--format=github. Plugin API frozen. (this release) - v0.2 —
.cursor/rules,.claude/rules, copilot-instructions, legacy.cursorrulesmigration; statictest(fixture-based, no model calls); autofix for SC101/SC102. - v1.0 — semver-frozen API,
--fixeverywhere,skillcraft doctor, pre-commit hook,--reversepromotion, PyPI trusted publishing. - v2 — live model evals (
skillcraft test --eval).
PRs welcome — especially new rules and format converters (each is a self-contained good-first-issue). See CONTRIBUTING.md and ARCHITECTURE.md. By contributing you agree to the Code of Conduct.