How Claude Code Skill Metadata Fields Are Parsed and Used: A Complete Technical Guide

Claude Code skill metadata fields are extracted from YAML frontmatter in SKILL.md files, parsed into Python dictionaries via BaseChecker._extract_frontmatter, validated against required schemas using checker classes, and consumed by both the validation scripts and the Astro documentation site to enforce constraints and render skill cards.

The Jeffallan/claude-skills repository manages Claude Code capabilities through structured markdown files. Each skill's metadata—including triggers, role definitions, and output formats—lives in a standardized YAML block that powers both automated validation and documentation generation. Understanding how these fields are parsed and used is essential for contributing new skills or extending the validation framework.

Where Skill Metadata Lives

Every skill resides in its own directory under skills/<skill-name>/, containing a mandatory SKILL.md file. This file must begin with a YAML frontmatter block delimited by triple dashes:

---
metadata:
  triggers: ["react", "component"]
  role: "frontend expert"
  scope: "file"
  output-format: "typescript"
  domain: "web development"
  related-skills: ["typescript-basics", "testing-react"]
---

The metadata map is the central data structure that subsequent parsing and validation stages consume.

Extracting and Parsing Metadata

The scripts/validate-skills.py file contains the core extraction logic in the BaseChecker class. The process follows a strict pipeline from raw markdown to structured data.

Locating the SKILL.md File

The validator first resolves the skill path and locates the markdown file:

skill_md = skill_path / "SKILL.md"

This logic resides in BaseChecker._extract_frontmatter at line 44 of validate-skills.py. If the file is missing, the checker immediately flags a validation error.

Splitting Frontmatter from Body

Once loaded, the raw content undergoes delimiter checking and splitting:

if not content.startswith("---"):
    # Error: Missing frontmatter delimiter

    return None

parts = content.split("---", 2)

# parts[0] = empty prefix

# parts[1] = YAML content

# parts[2] = Markdown body

This three-way split preserves the YAML metadata separately from the instructional content that follows.

YAML Parsing Implementation

The extracted YAML string passes through a compatibility layer that prefers PyYAML but falls back to a custom parser:

def parse_yaml(yaml_str: str) -> dict:
    if HAS_PYYAML:
        return yaml.safe_load(yaml_str) or {}
    return simple_yaml_parse(yaml_str)

This function, defined around line 24 in validate-skills.py, ensures the metadata block converts to a Python dictionary regardless of environment dependencies.

The final extraction wraps everything in a dataclass:

return FrontmatterResult(frontmatter, parts[2], skill_md)

Where frontmatter contains the parsed metadata dictionary ready for validation.

Validating Metadata Fields

After parsing, specialized checker classes validate the metadata dictionary against the schema defined in CLAUDE.md. Each checker inherits from BaseChecker and targets specific constraints.

Required Field Validation

The MetadataFieldsChecker ensures the metadata map contains all mandatory fields:

REQUIRED_METADATA_FIELDS = [
    "triggers",
    "role", 
    "scope",
    "output-format",
    "domain",
    "related-skills"
]

def check(self, result: FrontmatterResult) -> List[ValidationIssue]:
    metadata = result.frontmatter.get("metadata", {})
    for field in REQUIRED_METADATA_FIELDS:
        if field not in metadata:
            yield ValidationIssue(
                file=result.path,
                message=f"Missing required metadata field: {field}"
            )

This validation occurs in MetadataFieldsChecker.check and prevents incomplete skill definitions from passing CI.

Enum Constraint Enforcement

Two specialized checkers validate that certain fields contain only allowed values:

  • ScopeEnumChecker: Validates metadata.scope against VALID_SCOPES
  • OutputFormatEnumChecker: Validates metadata.output-format against VALID_OUTPUT_FORMATS

Both inherit from MetadataEnumChecker, which reads the allowed values from constants defined around line 150 in validate-skills.py. If a skill declares scope: invalid-value, the checker emits a validation error before the documentation site builds.

Cross-Skill Reference Checking

The CrossRefChecker uses the related-skills field to build a dependency graph:

def _check_orphans(self, all_skills: Dict[str, FrontmatterResult]):
    for skill_name, result in all_skills.items():
        related = result.frontmatter.get("metadata", {}).get("related-skills", [])
        for ref in related:
            if ref not in all_skills:
                yield ValidationIssue(
                    file=result.path,
                    message=f"Related skill '{ref}' does not exist"
                )

This ensures that metadata.related-skills only references valid, existing skills within the repository.

Consuming Metadata in the Documentation Site

While Python scripts handle validation, the Astro documentation site consumes the same metadata at build time. The configuration in site/src/content.config.ts defines the skills collection:

import { defineCollection, z } from 'astro:content';

const skills = defineCollection({
  schema: z.object({
    metadata: z.object({
      triggers: z.array(z.string()),
      role: z.string(),
      scope: z.enum(['file', 'project', 'global']),
      'output-format': z.string(),
      domain: z.string(),
      'related-skills': z.array(z.string())
    }).optional()
  })
});

Astro automatically parses the YAML frontmatter when loading skills/*/SKILL.md files. The TypeScript definitions in .astro/content.d.ts expose this metadata to components:

export interface RenderedContent {
  html: string;
  metadata?: {
    imagePaths: Array<string>;
    [key: string]: unknown;
  };
}

This enables the site to render skill cards showing the domain badge, filter search results by scope or output-format, and generate navigation links based on related-skills.

Practical Implementation Examples

Running the Validator for a Single Skill

Validate a specific skill from the command line:

python -m scripts.validate-skills --skill react-expert

This executes BaseChecker._extract_frontmatter to load skills/react-expert/SKILL.md, then runs MetadataFieldsChecker, ScopeEnumChecker, and CrossRefChecker to ensure compliance with the schema defined in CLAUDE.md.

Programmatically Reading Skill Metadata

Access parsed metadata in Python scripts:

from pathlib import Path
from scripts.validate_skills import BaseChecker

skill_path = Path("skills/react-expert")
result = BaseChecker._extract_frontmatter(skill_path)

if result:
    metadata = result.frontmatter.get("metadata", {})
    print("Domain:", metadata.get("domain"))
    print("Triggers:", metadata.get("triggers"))
    print("Related Skills:", metadata.get("related-skills"))

The BaseChecker._extract_frontmatter method is static and reusable, returning a FrontmatterResult dataclass containing the parsed dictionary, markdown body, and file path.

Accessing Metadata in Astro Components

Consume metadata in the documentation frontend:

---
import { getEntry } from 'astro:content';

const skill = await getEntry({ collection: 'skills', slug: 'react-expert' });
const { metadata } = skill?.data ?? {};
---

<h2>{skill?.title}</h2>

{metadata?.domain && (
  <span class="badge">{metadata.domain}</span>
)}

{metadata?.triggers && (
  <ul>
    {metadata.triggers.split(", ").map(trigger => (
      <li>{trigger}</li>
    ))}
  </ul>
)}

{metadata?.['related-skills'] && (
  <nav>
    <h3>Related Skills</h3>
    {metadata['related-skills'].map(related => (
      <a href={`/skills/${related}`}>{related}</a>
    ))}
  </nav>
)}

This TypeScript/Astro template renders the same metadata dictionary that the Python validator processes, ensuring consistency between validation and presentation layers.

Summary

  • Skill metadata resides in YAML frontmatter within skills/<skill-name>/SKILL.md files, nested under a top-level metadata key containing fields like triggers, role, scope, output-format, domain, and related-skills.
  • Extraction uses BaseChecker._extract_frontmatter in scripts/validate-skills.py, which splits the markdown on --- delimiters and parses the YAML content into a Python dictionary using parse_yaml (preferring PyYAML with a fallback to a custom parser).
  • Validation enforces schema compliance through specialized checkers: MetadataFieldsChecker ensures required fields exist, ScopeEnumChecker and OutputFormatEnumChecker validate against allowed values, and CrossRefChecker verifies that related-skills references point to existing skills.
  • Documentation consumption happens via Astro, which reads the same YAML frontmatter through site/src/content.config.ts and exposes the metadata to TypeScript components for rendering skill cards, search filters, and navigation links.

Frequently Asked Questions

What happens if a SKILL.md file is missing the metadata block?

The MetadataFieldsChecker emits a ValidationIssue error indicating that the metadata key is missing or incomplete. If the file lacks the --- delimiter entirely, BaseChecker._extract_frontmatter returns None, causing the validation pipeline to flag the file as having no parseable frontmatter.

Can I use custom fields in the metadata section?

While the MetadataFieldsChecker enforces a specific set of REQUIRED_METADATA_FIELDS, the YAML parser itself preserves all key-value pairs in the frontmatter dictionary. The Astro documentation site receives the complete metadata object, so additional fields can be accessed in TypeScript components, though they won't be validated by the Python checkers unless explicitly added to the schema in CLAUDE.md.

How does the validator handle YAML syntax errors?

The parse_yaml function in scripts/validate-skills.py attempts to use yaml.safe_load from PyYAML first. If PyYAML is unavailable, it falls back to simple_yaml_parse, a minimal custom parser. Syntax errors in the YAML block cause the parser to raise an exception, which the validation pipeline catches and reports as a ValidationIssue pointing to the specific file and error description.

What is the relationship between metadata validation and the Astro documentation site?

The Python validation scripts and the Astro site operate independently but consume the same source data. The Python checkers ensure that metadata fields conform to the schema before content is committed, while Astro's content collection (defined in site/src/content.config.ts) reads the valid YAML at build time to generate static pages. This separation ensures that only schema-compliant skills appear in the documentation, with the Python layer acting as a gatekeeper for the frontend.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →