A linter and sync tool for maintaining a library of Claude Code Agent Skills.
If you've written more than a handful of SKILL.md files, you've probably hit the same problems:
a skill's name: frontmatter drifts from its folder name, a skill balloons past the point where
the model reliably uses the whole thing, someone hardcodes C:\Users\yourname\... into a skill
body and it breaks the moment anyone else clones the repo, or you've got two copies of a skill
(one you edit, one that's actually loaded) that have quietly diverged.
claude-skill-kit is two small, dependency-free PowerShell scripts that catch all of that:
lint-skills.ps1— checks every skill for frontmatter correctness, name/folder match, a line-count cap, and hardcoded absolute paths.sync-skills.ps1— keeps a single "master" copy of your skills in sync with the deployed copy (or copies) that Claude Code / Cowork actually load, viarobocopy.
Both scripts are standalone: they resolve everything from their own location ($PSScriptRoot),
so you can drop this repo anywhere and point it at your own skills.
Claude Code loads skills from a project's .claude/skills/ folder. If you maintain skills across
multiple projects, or want a single browsable catalog of everything you've built, you end up
copy-pasting skills around — and copies drift. The fix is the same one you'd use for any
config-drift problem: one canonical place you edit, one tool that deploys it out.
your-repo/
├── skills/
│ └── core/ ← the master holder — edit skills here
│ ├── git-advanced/
│ │ └── SKILL.md
│ └── security-hardening/
│ ├── SKILL.md
│ └── reference.md
├── .claude/
│ └── skills/ ← the deployed copy — Claude Code loads from here
│ ├── git-advanced/
│ └── security-hardening/
├── manifest.json ← maps master subfolders -> deploy targets
├── lint-skills.ps1
└── sync-skills.ps1
Edit under skills/<set>/, run sync-skills.ps1 -Mode Push, and the deployed copy catches up.
If an agent self-edits a deployed skill live, -Mode Pull absorbs that change back into the
master so it stays the single source of truth.
For every SKILL.md under each configured skillset, lint-skills.ps1 checks:
| Check | What it catches |
|---|---|
| YAML frontmatter present | A skill with no --- block — Claude Code can't read its metadata at all |
name field present |
Missing name means the skill can't be identified |
name matches the folder name |
Copy-paste drift — you renamed the folder but not the frontmatter (or vice versa) |
description field present |
The description is how the model decides to invoke the skill — no description means it never triggers |
| Body ≤ 200 lines | Long skills are less reliably followed in full; the cap pushes you toward the extract-to-reference pattern (move worked examples to a sibling reference.md, keep the rules in SKILL.md) |
| No hardcoded absolute paths | C:\Users\..., /mnt/..., ~/.claude/... — anything that only works on the machine that wrote it |
Skills that legitimately need to exceed the 200-line cap (multi-stage orchestrator skills, for
example) can be listed in lint-exempt.txt — the linter reports them as accepted complexity
instead of flagging them.
# Lint every skillset defined in manifest.json
pwsh ./lint-skills.ps1
# Lint just one skillset
pwsh ./lint-skills.ps1 -Only core
# Check for drift between the master and the deployed copy (non-destructive, default mode)
pwsh ./sync-skills.ps1
# Deploy the master out to .claude/skills (additive — never deletes a deployed-only file)
pwsh ./sync-skills.ps1 -Mode Push
# Absorb changes an agent made directly to the deployed copy, back into the master
pwsh ./sync-skills.ps1 -Mode Pull
# Regenerate REGISTRY.md (a catalog of every skill + its description) from frontmatter
pwsh ./sync-skills.ps1 -Mode RegistryGiven a skill with a folder/name mismatch:
skills/core/git-advanced/SKILL.md
---
name: git-advanced-workflows <- doesn't match the folder name
description: Advanced git workflows...
---
> pwsh ./lint-skills.ps1
Linted 5 skills across 1 skillset(s).
1 issue(s):
[core/git-advanced] name 'git-advanced-workflows' != folder 'git-advanced'
Fix the name (or the folder), re-run, and you're clean:
Linted 5 skills across 1 skillset(s).
All clean.
skills/core/ ships five real, generic engineering skills so you can see the pattern and lint
something on first run without writing your own skill first:
git-advanced— worktrees, bisect, interactive rebase, hooks, recovery techniquestdd-mastery— Red-Green-Refactor cycle, test structure, and patterns across Jest/pytest/Gotesting-strategies— contract testing, snapshot testing, property-based testing, test doublessecurity-hardening— input validation, CSRF, CSP, secrets management, dependency auditingpython-best-practices— modern type hints, dataclasses vs. Pydantic, async patterns, packaging
security-hardening, testing-strategies, and python-best-practices each ship a sibling
reference.md demonstrating the extract-to-reference pattern: the SKILL.md carries the rules
and checklist, the reference file carries the full worked code examples, keeping the skill body
under the 200-line cap without losing the detail.
Maps each master subfolder to where it deploys:
{
"skillsets": [
{ "name": "core", "master": "skills\\core", "target": ".claude\\skills" }
]
}Add more entries to manage multiple skillsets (e.g. a core set everyone gets, plus a
project-specific set) or to fan the same master out to more than one deployed location.
manifest.json— the skillset map (see above).lint-exempt.txt— one skill-folder name per line; skills listed here are exempt from the 200-line cap. Ships as an empty template — add your own exemptions as your skills grow.REGISTRY.md— auto-generated catalog of every skill and its description. Regenerate withsync-skills.ps1 -Mode Registryafter adding or editing a skill; don't hand-edit it.
- Windows PowerShell 5.1+ or PowerShell 7+ (
pwsh) robocopy(ships with Windows; used bysync-skills.ps1for the Push/Pull copy)- Pester 5.x, only if you want to run the test suite (
tests/)
Install-Module Pester -Scope CurrentUser -MinimumVersion 5.0 -Force # if not already installed
Invoke-Pester ./tests/lint-skills.Tests.ps1 -Output DetailedThe suite builds small fixture skill trees under Pester's TestDrive to exercise each check in
isolation (missing file, missing name, name/folder mismatch, missing description, over-cap body,
exempted over-cap body, hardcoded path) and finishes with a smoke test that lints this repo's own
bundled skills and asserts a clean report.
CI (.github/workflows/ci.yml) runs the linter and the Pester suite on windows-latest on every
push and pull request.
MIT — see LICENSE.