skill-validator

Validate Agent Skills against best practices and specification requirements. Use when reviewing skills, before publishing, or to audit existing skills.

$ 安裝

git clone https://github.com/dopsonbr/agent-kit /tmp/agent-kit && cp -r /tmp/agent-kit/content/skills/skill-validator ~/.claude/skills/agent-kit

// tip: Run this command in your terminal to install the skill


name: skill-validator description: Validate Agent Skills against best practices and specification requirements. Use when reviewing skills, before publishing, or to audit existing skills. license: MIT metadata: author: agent-kit version: "1.1.0"

Skill Validator

Validate Agent Skills for correctness, completeness, and best practices.

When to Use

  • Before committing a new skill
  • After editing an existing skill
  • To audit all skills in a project
  • During code review of skill PRs

Validation Levels

🔴 Errors (Must Fix)

These will cause the skill to fail:

CheckRule
name existsRequired field in frontmatter
name formatLowercase, hyphens only, max 64 chars
name no reservedCannot contain "anthropic" or "claude"
description existsRequired field in frontmatter
description lengthMax 1024 characters
No XML in frontmattername and description cannot contain XML tags
SKILL.md existsMust have main instruction file

🟡 Warnings (Should Fix)

These reduce effectiveness:

CheckRule
Description has "when"Should include trigger conditions
Has examplesShould have concrete usage examples
Token limitSKILL.md body should be < 5000 tokens
Referenced files existAll [text](path) links should resolve
Has purpose sectionShould explain what skill does
Slash command existsCorresponding command file should exist
Command references skillCommand should reference the skill's SKILL.md
agent-kit command prefixCommands in content/commands/ must use ak- prefix
No name conflictsCommand name must not conflict with existing skill names

🟢 Suggestions (Nice to Have)

Polish and completeness:

CheckRule
Has related skillsLinks to complementary skills
Consistent formattingHeaders, code blocks properly formatted
Version in metadataHelps track changes
License specifiedClear usage terms

Usage

Validate Single Skill

User: Validate the create-plan skill

Claude: [Reads content/skills/plan-create/SKILL.md]
[Runs validation checks]
[Reports results]

Validate All Skills

User: Validate all skills in this project

Claude: [Scans .claude/skills/ or content/skills/]
[Validates each skill]
[Produces summary report]

Validate Before Commit

User: Check if my new skill is ready to commit

Claude: [Validates skill]
[If errors: lists what to fix]
[If clean: confirms ready]

Validation Process

Step 1: Parse Frontmatter

// 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");

Step 2: Validate Name

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'");
}

Step 3: Validate Description

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");

Step 4: Check Structure

// 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");
}

Step 5: Validate Links

// 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}")`);
  }
}

Step 6: Validate Slash Command

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");
  }
}

Step 7: Validate Command Naming

// 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}'`);
  }
}

Output Format

Single Skill Report

╭─────────────────────────────────────────╮
│  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)

Multi-Skill Report

╭─────────────────────────────────────────╮
│  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

Validation Script

For automated validation, use the script:

./scripts/validate-skill.ts path/to/skill

See scripts/validate-skill.ts for implementation.

Quick Checklist

Before publishing any skill:

  • name is lowercase with hyphens only
  • description includes what AND when
  • SKILL.md has examples section
  • All file links resolve correctly
  • Body is under 5000 tokens
  • Slash command exists (e.g., commands/{skill-name}.md)
  • Command references @skills/{skill-name}/SKILL.md
  • agent-kit commands use ak- prefix (e.g., ak-create-plan.md)
  • No command/skill name conflicts
  • Tested in fresh Claude Code session

Integration with skill-creator

When using /create-skill, validation runs automatically before finalizing.

Related Skills

  • skill-creator - Create new skills (validates on creation)
  • doc-contents - Document skill directories