Markdown Post Frontmatter Validation
Concept of the skill
What it is: The project-specific validation discipline for the YAML frontmatter on markdown posts.
Mental model: Frontmatter is a typed interface between content files and the site runtime.
Why it exists: Routing, indexes, tags, dates, and previews all depend on frontmatter being complete and unambiguous.
What it is NOT: It is not general YAML schema design, parser performance work, or debugging a specific failed build.
Adjacent concepts: Content schemas, slug derivation, controlled vocabularies, date normalization.
One-line analogy: It is the checklist that makes every post safe for the build to consume.
Common misconception: If the markdown renders, the frontmatter is good enough; metadata can break listing pages even when body content renders.
Coverage
- Required-field enforcement — every post must declare
title, date, slug, and tags; missing fields fail the build at parse time
- Date format discipline — ISO 8601 with explicit timezone (
2026-05-06T12:00:00Z); ambiguous formats like 2026-05-06 or 5/6/26 are rejected
- Slug-to-path consistency — the
slug field must match the post's directory name; out-of-sync slugs cause silent route conflicts
- Controlled-vocabulary tagging — every tag in the post's
tags array must appear in lib/content/tag-vocabulary.ts; lowercase, hyphen-separated, no synonyms
- Schema evolution — when
lib/content/schema.ts changes, every post's frontmatter is re-validated; existing posts that violate the new schema are flagged before the next build runs
- Reserved-field protection — fields like
_id, _internal, or any underscore-prefixed key are reserved for the build pipeline and rejected in author-facing frontmatter
Philosophy of the skill
The frontmatter block is the contract every post makes with the site's index, the router, and the renderer. If that contract is loose — if posts can omit fields, use ambiguous dates, or invent ad-hoc tags — the index drifts, routes silently overlap, and the search surface degrades. The cost of catching frontmatter bugs at build time is one re-run; the cost of catching them in production is a broken page or a missing entry in the archive. The rule is: validate at parse time, fail loud, and keep the schema small enough that authors can hold it in their head.
Key Files
| File |
Purpose |
content/posts/_template.md |
The canonical template every new post copies — its frontmatter is the worked example of every required field |
lib/content/schema.ts |
The TypeScript schema (Zod or equivalent) that runtime validation calls |
lib/content/parse-frontmatter.ts |
The thin wrapper that reads the YAML block and runs schema.parse() — the failure surface for build-time errors |
Verification
Before merging any change to a post's frontmatter or to the schema:
Do NOT Use When
| Use instead |
When |
| (a generic schema-design skill) |
The task is designing a new YAML schema for an unrelated domain |
debugging |
A specific build is failing and you need to reproduce the validation error from logs |
documentation |
The task is writing a runbook or contributor doc about the frontmatter format |
refactor |
The task is restructuring parse-frontmatter.ts without changing the validation contract |
1---2name: markdown-post-frontmatter-validation3description: Use when authoring or reviewing the frontmatter of a markdown post — checking required fields (title, date, slug, tags), validating against the content schema in `lib/content/schema.ts`, catching ambiguous date formats or tags not in the controlled vocabulary, and ensuring the slug matches the file path. Activate this skill whenever the task touches files under `content/posts/**/*.md`, the `parsePostFrontmatter()` helper, or any code path that reads YAML frontmatter from a content file. Do NOT use for general YAML schema design (use a generic schema-design skill) or for chasing a specific build-time validation failure (use debugging).4license: MIT5---67# Markdown Post Frontmatter Validation89## Concept of the skill1011**What it is:** The project-specific validation discipline for the YAML frontmatter on markdown posts.12**Mental model:** Frontmatter is a typed interface between content files and the site runtime.13**Why it exists:** Routing, indexes, tags, dates, and previews all depend on frontmatter being complete and unambiguous.14**What it is NOT:** It is not general YAML schema design, parser performance work, or debugging a specific failed build.15**Adjacent concepts:** Content schemas, slug derivation, controlled vocabularies, date normalization.16**One-line analogy:** It is the checklist that makes every post safe for the build to consume.17**Common misconception:** If the markdown renders, the frontmatter is good enough; metadata can break listing pages even when body content renders.1819## Coverage2021- Required-field enforcement — every post must declare `title`, `date`, `slug`, and `tags`; missing fields fail the build at parse time22- Date format discipline — ISO 8601 with explicit timezone (`2026-05-06T12:00:00Z`); ambiguous formats like `2026-05-06` or `5/6/26` are rejected23- Slug-to-path consistency — the `slug` field must match the post's directory name; out-of-sync slugs cause silent route conflicts24- Controlled-vocabulary tagging — every tag in the post's `tags` array must appear in `lib/content/tag-vocabulary.ts`; lowercase, hyphen-separated, no synonyms25- Schema evolution — when `lib/content/schema.ts` changes, every post's frontmatter is re-validated; existing posts that violate the new schema are flagged before the next build runs26- Reserved-field protection — fields like `_id`, `_internal`, or any underscore-prefixed key are reserved for the build pipeline and rejected in author-facing frontmatter2728## Philosophy of the skill2930The frontmatter block is the contract every post makes with the site's index, the router, and the renderer. If that contract is loose — if posts can omit fields, use ambiguous dates, or invent ad-hoc tags — the index drifts, routes silently overlap, and the search surface degrades. The cost of catching frontmatter bugs at build time is one re-run; the cost of catching them in production is a broken page or a missing entry in the archive. The rule is: validate at parse time, fail loud, and keep the schema small enough that authors can hold it in their head.3132## Key Files3334| File | Purpose |35|---|---|36| `content/posts/_template.md` | The canonical template every new post copies — its frontmatter is the worked example of every required field |37| `lib/content/schema.ts` | The TypeScript schema (Zod or equivalent) that runtime validation calls |38| `lib/content/parse-frontmatter.ts` | The thin wrapper that reads the YAML block and runs `schema.parse()` — the failure surface for build-time errors |3940## Verification4142Before merging any change to a post's frontmatter or to the schema:4344- [ ] Every post has the four required fields: `title`, `date`, `slug`, `tags`45- [ ] `date` is ISO 8601 with timezone (no naked `YYYY-MM-DD`, no locale-formatted dates)46- [ ] `slug` matches the post's directory name exactly — not derived from `title` at runtime47- [ ] Every tag in `tags` is present in `lib/content/tag-vocabulary.ts` (run `npm run check:tags` to confirm)48- [ ] No underscore-prefixed fields (`_id`, `_internal`, etc.) — those are reserved for the pipeline49- [ ] Schema changes (`lib/content/schema.ts`) are paired with a `npm run validate:posts` pass against the entire `content/posts/**/*.md` set5051## Do NOT Use When5253| Use instead | When |54|---|---|55| (a generic schema-design skill) | The task is designing a new YAML schema for an unrelated domain |56| `debugging` | A specific build is failing and you need to reproduce the validation error from logs |57| `documentation` | The task is writing a runbook or contributor doc about the frontmatter format |58| `refactor` | The task is restructuring `parse-frontmatter.ts` without changing the validation contract |