Validate Agent Skills against best practices and specification requirements. Use when reviewing skills, before publishing, or to audit existing skills.
Validate Agent Skills for correctness, completeness, and best practices.
These will cause the skill to fail:
| Check | Rule |
|---|---|
name exists |
Required field in frontmatter |
name format |
Lowercase, hyphens only, max 64 chars |
name no reserved |
Cannot contain "anthropic" or "claude" |
description exists |
Required field in frontmatter |
description length |
Max 1024 characters |
| No XML in frontmatter | name and description cannot contain XML tags |
| SKILL.md exists | Must have main instruction file |
These reduce effectiveness:
| Check | Rule |
|---|---|
| Description has "when" | Should include trigger conditions |
| Has examples | Should have concrete usage examples |
| Token limit | SKILL.md body should be < 5000 tokens |
| Referenced files exist | All [text](path) links should resolve |
| Has purpose section | Should explain what skill does |
| Slash command exists | Corresponding command file should exist |
| Command references skill | Command should reference the skill's SKILL.md |
| agent-kit command prefix | Commands in content/commands/ must use ak- prefix |
| No name conflicts | Command name must not conflict with existing skill names |
Polish and completeness:
| Check | Rule |
|---|---|
| Has related skills | Links to complementary skills |
| Consistent formatting | Headers, code blocks properly formatted |
| Version in metadata | Helps track changes |
| License specified | Clear usage terms |
User: Validate the create-plan skill
Claude: [Reads content/skills/plan-create/SKILL.md]
[Runs validation checks]
[Reports results]
User: Validate all skills in this project
Claude: [Scans .claude/skills/ or content/skills/]
[Validates each skill]
[Produces summary report]
User: Check if my new skill is ready to commit
Claude: [Validates skill]
[If errors: lists what to fix]
[If clean: confirms ready]
// Extract YAML frontmatter
const frontmatter = parseFrontmatter(skillMd);
// Check required fields
if (!frontmatter.name) error("Missing 'name' in frontmatter");
if (!frontmatter.description) error("Missing 'description' in frontmatter");
const name = frontmatter.name;
// Length check
if (name.length > 64) error("Name exceeds 64 characters");
// Format check
if (!/^[a-z0-9-]+$/.test(name)) {
error("Name must be lowercase letters, numbers, and hyphens only");
}
// Reserved words
if (name.includes("anthropic") || name.includes("claude")) {
error("Name cannot contain 'anthropic' or 'claude'");
}
const desc = frontmatter.description;
// Length check
if (desc.length > 1024) error("Description exceeds 1024 characters");
// Trigger words check
const hasTrigger = /use when|use for|when you|if you/i.test(desc);
if (!hasTrigger) warn("Description should include trigger conditions");
// Token estimate (rough: 4 chars = 1 token)
const bodyTokens = skillBody.length / 4;
if (bodyTokens > 5000) warn(`SKILL.md is ~${bodyTokens} tokens (recommended < 5000)`);
// Check for examples
if (!skillBody.includes("## Example")) {
warn("No examples section found");
}
// Check for purpose
if (!skillBody.match(/## (Purpose|Overview|What)/)) {
warn("No purpose/overview section found");
}
// Find all markdown links
const links = skillBody.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g);
for (const [, text, path] of links) {
if (path.startsWith("http")) continue; // Skip external links
const fullPath = resolve(skillDir, path);
if (!exists(fullPath)) {
error(`Broken link: ${path} (referenced as "${text}")`);
}
}
const skillName = frontmatter.name;
// Determine command location based on skill location
// .claude/skills/{name}/ → .claude/commands/{name}.md
// content/skills/{name}/ → content/commands/ak-{name}.md (with ak- prefix!)
const isAgentKit = skillDir.includes('content/skills');
const commandName = isAgentKit ? `ak-${skillName}` : skillName;
const commandPath = skillDir
.replace('/skills/', '/commands/')
.replace(`/${skillName}/`, `/${commandName}.md`);
// Check command exists
if (!exists(commandPath)) {
warn(`No slash command found at ${commandPath}`);
if (isAgentKit) {
warn("agent-kit commands must use 'ak-' prefix: ak-{skill-name}.md");
}
} else {
// Verify command references the skill
const commandContent = read(commandPath);
if (!commandContent.includes(`@skills/${skillName}/SKILL.md`)) {
warn("Command does not reference the skill's SKILL.md");
}
}
// Check for agent-kit command prefix
if (isAgentKit) {
const commandFiles = listDir('content/commands/');
for (const file of commandFiles) {
if (!file.startsWith('ak-')) {
warn(`Command ${file} must use 'ak-' prefix for agent-kit distribution`);
}
}
}
// Check for command/skill name conflicts
const allSkillNames = listDir(skillsDir).map(d => d.name);
const allCommandNames = listDir(commandsDir).map(f => f.replace('.md', ''));
for (const cmd of allCommandNames) {
const baseName = cmd.replace(/^ak-/, '');
// Skip if this is the matching command for a skill
if (allSkillNames.includes(baseName)) continue;
// Check for conflicts (same name as different skill)
if (allSkillNames.includes(cmd)) {
warn(`Command '${cmd}' conflicts with skill name '${cmd}'`);
}
}
╭─────────────────────────────────────────╮
│ Skill Validation: create-plan │
╰─────────────────────────────────────────╯
✅ PASSED
Errors: 0
Warnings: 1
Info: 2
⚠️ Warnings:
• Description could include more trigger words
ℹ️ Suggestions:
• Consider adding 'related skills' section
• Add version to metadata
Files checked:
✓ SKILL.md (156 lines, ~620 tokens)
✓ assets/plan-template.md
Command:
✓ commands/create-plan.md (references skill correctly)
╭─────────────────────────────────────────╮
│ Skill Validation Summary │
╰─────────────────────────────────────────╯
Skills checked: 4
✅ create-plan 0 errors, 1 warning
✅ doc-contents 0 errors, 0 warnings
✅ skill-creator 0 errors, 0 warnings
❌ my-broken-skill 2 errors, 3 warnings
Overall: 3 passed, 1 failed
For automated validation, use the script:
./scripts/validate-skill.ts path/to/skill
See scripts/validate-skill.ts for implementation.
Before publishing any skill:
name is lowercase with hyphens onlydescription includes what AND whencommands/{skill-name}.md)@skills/{skill-name}/SKILL.mdak- prefix (e.g., ak-create-plan.md)When using /create-skill, validation runs automatically before finalizing.
skill-creator - Create new skills (validates on creation)doc-contents - Document skill directories