# SKILL.md File Format: Required YAML Frontmatter Structure for Vercel Skills

> Learn the required SKILL.md file format for Vercel. Understand the essential YAML frontmatter structure including name and description fields for your projects.

- Repository: [Vercel Labs/skills](https://github.com/vercel-labs/skills)
- Tags: api-reference
- Published: 2026-04-23

---

**A valid SKILL.md file must start with YAML frontmatter delimited by triple dashes (`---`), containing mandatory `name` and `description` string fields, followed by optional markdown content.**

The `vercel-labs/skills` CLI uses strict parsing rules to discover and validate agent skills. This guide covers the exact file structure, required fields, and validation logic implemented in the source code.

## File Location and Naming Requirements

The [`SKILL.md`](https://github.com/vercel-labs/skills/blob/main/SKILL.md) file must follow precise naming and placement conventions for the CLI scanner to detect it:

- **Filename**: Exactly [`SKILL.md`](https://github.com/vercel-labs/skills/blob/main/SKILL.md) (case-sensitive)
- **Location**: Root of the skill directory or a subdirectory discoverable by the scanner
- **Discovery**: The `skills` CLI walks directories and parses any file named [`SKILL.md`](https://github.com/vercel-labs/skills/blob/main/SKILL.md)

In [`src/cli.ts`](https://github.com/vercel-labs/skills/blob/main/src/cli.ts) (lines 40-44), the `init` command generates the file at [`./SKILL.md`](https://github.com/vercel-labs/skills/blob/main/./SKILL.md) or `<name>/SKILL.md`:

```typescript
const skillContent = `---
name: ${skillName}
description: A brief description of what this skill does
---
...
`;

```

## YAML Frontmatter Delimiters

The frontmatter block must use exact delimiter syntax. The parser in [`src/frontmatter.ts`](https://github.com/vercel-labs/skills/blob/main/src/frontmatter.ts) uses a strict regex pattern:

```typescript
// src/frontmatter.ts – lines 12-15
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);

```

**Delimiter rules:**
- Opening delimiter: exactly `---` on its own line (no leading whitespace)
- Closing delimiter: exactly `---` on its own line
- Line endings: `\n` or `\r\n` both accepted
- Content between delimiters: valid YAML

Any deviation—leading spaces before the opening `---`, missing closing delimiter, or extra characters on the same line—causes the file to be rejected or parsed as plain markdown without frontmatter data.

## Mandatory Frontmatter Fields

Two fields are strictly required for skill discovery. The validation logic in [`src/skills.ts`](https://github.com/vercel-labs/skills/blob/main/src/skills.ts) explicitly checks for these:

```typescript
// src/skills.ts – lines 33-44
const content = await readFile(skillMdPath, 'utf-8');
const { data } = parseFrontmatter(content);

if (!data.name || !data.description) return null;
if (typeof data.name !== 'string' || typeof data.description !== 'string') return null;

```

| Field | Type | Purpose |
|-------|------|---------|
| `name` | string | Unique identifier for the skill (used in CLI commands and URLs) |
| `description` | string | Human-readable summary displayed in skill listings |

**Critical:** Both values must be YAML strings. Numbers, booleans, null values, or missing keys cause immediate rejection—the function returns `null` and the skill is not registered.

## Optional Frontmatter Metadata

Beyond the mandatory fields, any additional YAML keys are accepted and stored. The `metadata` key receives special handling but remains optional:

```typescript
// src/skills.ts – metadata extraction
metadata: data.metadata

```

Common optional fields include:

- `metadata`: Nested object for tooling-specific configuration
- `version`: Semantic version string
- `author`: Creator attribution
- `tags`: List of category keywords
- `license`: SPDX identifier

These values have no validation—they are passed through as-is to consuming tools and agents.

## Content After Frontmatter

Everything following the closing `---` delimiter is treated as the skill's **instructional content**. This section is not parsed for discovery but serves critical purposes:

- **Agent instructions**: Markdown describing how the AI should use the skill
- **Usage examples**: Code snippets and scenarios
- **When to use**: Conditions for skill activation

The raw content is preserved for hashing and installation:

```typescript
// src/skills.ts – raw content storage
rawContent: content

```

## Complete SKILL.md Examples

### Minimal Valid File

```yaml
---
name: code-reviewer
description: Automated code review for pull requests
---

# Code Reviewer

Review pull request diffs and provide constructive feedback.

## When to use

- When a PR is opened or updated
- When explicitly requested by a developer

## Instructions

1. Analyze the diff for bugs, security issues, and style violations
2. Comment on specific lines with clear explanations
3. Suggest concrete improvements with code examples

```

### Full Featured Example

```yaml
---
name: image-optimiser
description: Optimise images using Sharp before upload
metadata:
  internal: false
  version: 1.2.0
  tags: [image, optimisation, sharp]
  author: Vercel Labs
  license: MIT
---

# Image Optimiser

Reduce image file sizes without perceptible quality loss using the Sharp library.

## When to use

Run this skill when:
- Uploading images to a CDN
- Processing user-generated content
- Preparing assets for production deployment

## Instructions

1. **Detect image files** in the target directory (`.jpg`, `.png`, `.webp`)
2. **Run Sharp** with quality settings: `sharp(input).jpeg({ quality: 80, progressive: true })`
3. **Replace originals** with optimized versions
4. **Log savings** (original vs. optimized byte size)

## Example

```javascript
const sharp = require('sharp');
const stats = await sharp('photo.jpg')
  .resize(1920, null, { withoutEnlargement: true })
  .jpeg({ quality: 85, mozjpeg: true })
  .toFile('photo-optimized.jpg');

```

```

## Summary

- **File naming**: Exactly [`SKILL.md`](https://github.com/vercel-labs/skills/blob/main/SKILL.md) at the skill directory root
- **Frontmatter delimiters**: `---` on dedicated lines with no leading whitespace
- **Required fields**: `name` and `description` must be present and string-typed
- **Optional metadata**: Any additional YAML keys accepted, including nested `metadata` object
- **Content body**: Markdown instructions follow the closing delimiter—not parsed for discovery but preserved for hashing and installation

Failure to meet any mandatory requirement causes the skill to be silently ignored by the discovery scanner in [`src/skills.ts`](https://github.com/vercel-labs/skills/blob/main/src/skills.ts).

## Frequently Asked Questions

### What happens if I forget the `description` field?

The skill is rejected. In [`src/skills.ts`](https://github.com/vercel-labs/skills/blob/main/src/skills.ts), the validation logic explicitly returns `null` when `data.description` is missing or not a string, causing the skill to be excluded from listings and unavailable for installation.

### Can I use JSON instead of YAML in the frontmatter?

No. The parser in [`src/frontmatter.ts`](https://github.com/vercel-labs/skills/blob/main/src/frontmatter.ts) uses `parseYaml()` exclusively on the content between `---` delimiters. JSON syntax will cause a YAML parsing error and the file will fail to load.

### Is the content after the frontmatter used by the CLI?

Yes, but not for discovery. The raw markdown content is stored in `rawContent` and used for generating installation hashes and providing the full skill definition to agents. The CLI does not parse markdown headings or structure—it treats everything after the closing `---` as an opaque string.