Naming checks validate skill name requirements defined in the Agent Skills specification.
Check List
This dimension includes 1 behavioral check and 2 schema checks (all spec-required).
| Check ID | Severity | Spec | What It Validates |
|---|
naming.required | ERROR | Yes | Name field is present in frontmatter |
naming.format | ERROR | Yes | Name follows format rules |
naming.matches-directory | ERROR | Yes | Name matches parent directory |
naming.required
Severity: ERROR | Spec Required: Yes | Type: Schema Check
Validates that the name field is present in frontmatter.
What It Checks
- Verifies frontmatter exists
- Checks that
name field is present
- Checks that
name is not empty or whitespace-only
Schema Definition
FieldRule(
check_id="naming.required",
check_name="Name Required",
description="Name field is present in frontmatter",
severity=Severity.ERROR,
dimension=EvalDimension.NAMING,
spec_required=True,
field_name="name",
source="metadata",
required=True,
no_metadata_context="check name",
fail_message="Name field is missing or empty in frontmatter",
pass_message="Name field present: '{value}'",
)
Example
# ❌ Fails - no name field
---
description: My skill
---
# ❌ Fails - empty name
---
name: ""
description: My skill
---
# ✅ Passes
---
name: my-skill
description: My skill
---
Severity: ERROR | Spec Required: Yes | Type: Schema Check
Validates that the name follows the Agent Skills specification format rules.
- Lowercase only - letters and numbers
- Hyphens allowed - but not at start or end
- No consecutive hyphens -
-- is not allowed
- Max 64 characters
- Pattern:
^[a-z0-9][a-z0-9-]*[a-z0-9]$ or ^[a-z0-9]$ (single char)
Schema Definition
FieldRule(
check_id="naming.format",
check_name="Name Format",
description="Name is lowercase, hyphen-separated, max 64 chars",
severity=Severity.ERROR,
dimension=EvalDimension.NAMING,
spec_required=True,
field_name="name",
source="metadata",
required=True,
max_length=64,
regex_pattern=r"^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
regex_fail_message=(
"Name must be lowercase letters, numbers, and hyphens only, "
"and must not start or end with a hyphen"
),
no_consecutive="--",
no_consecutive_message="Name should not contain consecutive hyphens",
no_metadata_context="validate name",
fail_message="No name to validate",
pass_message="Name '{value}' follows format rules",
)
Examples
# ✅ Valid names
---
name: my-skill
---
---
name: api-helper-v2
---
---
name: doc-writer
---
---
name: x
---
# ❌ Invalid names
---
name: My-Skill # Uppercase not allowed
---
---
name: -my-skill # Cannot start with hyphen
---
---
name: my-skill- # Cannot end with hyphen
---
---
name: my--skill # No consecutive hyphens
---
---
name: my_skill # Underscores not allowed
---
The format check accumulates multiple errors. If a name violates several rules (e.g., too long AND has consecutive hyphens), all violations will be reported in a single failure message.
naming.matches-directory
Severity: ERROR | Spec Required: Yes | Type: Behavioral Check
Validates that the skill name matches the parent directory name (spec requirement).
What It Checks
- Extracts name from frontmatter
- Gets parent directory name
- Normalizes both using NFKC Unicode normalization
- Compares for exact match
Why NFKC Normalization?
Unicode normalization ensures consistent handling of special characters across different filesystems:
- macOS uses NFD (decomposed) normalization
- Linux/Windows use NFC (composed) normalization
- NFKC provides compatibility normalization
Implementation
import unicodedata
def run(self, skill: Skill) -> CheckResult:
if skill.metadata is None or not skill.metadata.name:
return self._fail(
"No name to validate",
location=self._skill_md_location(skill),
)
name = unicodedata.normalize("NFKC", skill.metadata.name)
directory_name = unicodedata.normalize("NFKC", skill.path.name)
if name != directory_name:
return self._fail(
f"Name '{name}' does not match directory name '{directory_name}'",
details={"name": name, "directory": directory_name},
location=self._skill_md_location(skill),
)
return self._pass(
f"Name '{name}' matches directory name",
location=self._skill_md_location(skill),
)
Example
# ✅ Correct structure
my-skill/
SKILL.md # name: my-skill
# ❌ Name mismatch
my-skill/
SKILL.md # name: different-name
This check ensures that skill directories are self-describing. The directory name should always match the skill name for easy identification.
File Location
Naming checks are implemented in:
- Behavioral check:
src/skill_lab/checks/static/naming.py (NameMatchesDirectoryCheck)
- Schema checks:
src/skill_lab/checks/static/schema.py (FRONTMATTER_SCHEMA list)