SKILL.md File Format: Required YAML Frontmatter Structure for Vercel Skills
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 file must follow precise naming and placement conventions for the CLI scanner to detect it:
- Filename: Exactly
SKILL.md(case-sensitive) - Location: Root of the skill directory or a subdirectory discoverable by the scanner
- Discovery: The
skillsCLI walks directories and parses any file namedSKILL.md
In src/cli.ts (lines 40-44), the init command generates the file at ./SKILL.md or <name>/SKILL.md:
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 uses a strict regex pattern:
// 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:
\nor\r\nboth 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 explicitly checks for these:
// 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:
// src/skills.ts – metadata extraction
metadata: data.metadata
Common optional fields include:
metadata: Nested object for tooling-specific configurationversion: Semantic version stringauthor: Creator attributiontags: List of category keywordslicense: 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:
// src/skills.ts – raw content storage
rawContent: content
Complete SKILL.md Examples
Minimal Valid File
---
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
---
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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →