Your frontmatter has never been checked


I have a file in my showcase site called pipeline.md. It has no frontmatter. Not a sparse block, not a missing field. The file opens on an H1 and goes straight into content.

Vale looks at it. Doc Detective looks at it. GitHub Actions runs both on every push. Nothing complains. It builds, it renders, it ships.

That file is the one that explains my documentation pipeline. It’s the page I’d hand an AI agent first. It’s also the least-described file in the repo, and I didn’t know that until last week.

Frontmatter is the only thing in your repo that nothing checks

Everything else fails loudly. A broken link fails the link checker. A malformed code fence fails the build. A sentence Vale hates gets flagged in the pull request. A procedure that no longer works fails Doc Detective.

Frontmatter is hand-typed and validated by nothing. Miss a field and the page still builds. Fat-finger a date and the page still renders. There’s no error surface at all, which means the drift is invisible by design.

Manny Silva — the person behind Docs as Tests and Doc Detective — just shipped a tool for exactly this. It’s called docmeta, and if you want the context first, his Doc Detective demo is where the thinking comes from. It reads the frontmatter in your files, validates it against a JSON Schema, and fails your build when a required field is missing or malformed. It won’t grade your prose or check your links. Metadata in, pass/fail out.

I ran it against oddlittlebird/showcase-site. Thirty files, Docusaurus 3.10.1.

The first run tells you nothing, and that’s the point

docmeta ships seven schemas, including one for each Docusaurus content type. I mapped docs, blog, and pages to theirs and ran it:

​
30 files checked, 30 passed, 0 failed, 0 errors
​

Clean sweep. Docusaurus marks no frontmatter field as mandatory, so its schemas check the shape of fields a page already carries rather than demanding any. Nothing that was already building could fail.

Then I wrote my own schema. Eleven lines, requiring title and description. Two fields I already use, just inconsistently:

​
24 of 30 files fail
​

Six pass. All six are in src/pages. Not one file in docs/ or blog/ carries a description. Fifteen blog posts, zero descriptions. I would have guessed most of them had one.

One correction while you’re trying this: running docmeta validate with no config falls back to Google’s OKF schema, which requires type. Nothing in my repo declares type, so the bare default failed all thirty files. Both things are true at once. It checks almost nothing, and it fails everything.

This matters long before you get anywhere near agents

Take last_reviewed. A staleness report, meaning every page not reviewed in twelve months, is the easiest case you’ll ever make to a manager for content debt work. It’s also entirely dependent on that date being real on every page.

So I dropped a file into the repo with last_reviewed: 2024-13-45. Month thirteen, day forty-five. Under the Docusaurus schema, it passed. Under mine:

​
/last_reviewed must match format "date" (line 4)
​

Exact field, exact line. That’s the whole argument in one error message. An audit built on unvalidated metadata doesn’t error. It lies. It quietly under-reports, and you take the number to your manager.

The same holds everywhere else metadata is load-bearing. “Our how-to guides get four times the traffic of our explanations” is a strong argument and it’s only answerable if type is reliable on every page. Translation scope gets pulled from frontmatter, so a missing flag means a page that never gets localized, or one you paid to localize twice. Conditional publishing decides what ships in the enterprise build.

None of that is new, and none of it involves an agent. All of it fails silently.

Pick one vocabulary, then stack the other

docmeta ships schemas for both Diátaxis and The Good Docs Project templates. Both claim type, so stacking them narrows the accepted values to the intersection of the two, which is almost never what anyone wants. Pick one.

Fabrizio Ferri Benedetti’s Seven-Action model claims action instead: Appraise, Understand, Explore, Practice, Remember, Develop, Troubleshoot. It describes what a reader came to do rather than what you produced, so it composes with either content-type vocabulary instead of competing with it. It also requires nothing, which makes it the safest one to switch on first. It rules that an action, if present, is legitimate, without insisting on one.

Setup, and one thing that will bite you

A config file at the repo root with per-directory overrides makes it one command instead of three. docmeta validate -f github emits error annotations, so it dropped into my existing Actions workflow next to Vale and Doc Detective with no wrapper. Under two minutes, including reading the schema list.

The warning: the Get started page says Node 20 or newer. The package has required Node 24 since its first release. npm treats an engine mismatch as a warning rather than an error, so on Node 20 the install reports success and docmeta --version answers normally, and you’ll spend a while wondering why nothing behaves. I’ve reported it.

The agent part, briefly

The fields your staleness report reads are the fields a retrieval system filters on. Whether a page declares itself a tutorial or a reference decides whether an AI agent walks someone through it step by step or pulls a single parameter out of it. An untyped page doesn’t get rejected. It gets retrieved for the wrong job.

Which brings me back to pipeline.md. Zero frontmatter, three tools, no complaints. The page I’d most want an agent to read correctly is the one carrying the least information about what it is.

Run npx docmeta validate against your docs directory. Nothing to install. Then hit reply and tell me your failure count. I want to know whether 24 of 30 is normal or whether I’m the worst case on this list.


You might notice something new below: my first sponsor. If you want to support this newsletter, take a look at what Superhuman is offering.

Diana Payton

Diana Payton

I'm a writer who helps technical professionals transition into technical writing. I also create content on my YouTube channels: Technical Writing Uncensored and Make, Mend, Grow with Diana.

Read more from Diana Payton

Hi Reader, I've hired a lot of technical writers. Yes, I read your LinkedIn recommendations. Layoffs are everywhere right now, and they suck. Some of you got the surprise calendar invite this month, and some of you are still at your desks wondering who's next. Either way, the people who can vouch for your work are about to scatter. If you were laid off Ask for portfolio samples, and get the answer in writing. Yes, NDAs are a thing. Most of them come down to "do not share company material...

Hi Reader, Grocery receipts keep getting longer while the bags get lighter, and "recession" is back in the news. So I went back about a hundred years to see what people actually did during the Great Depression, and which of those habits still hold up. Most of them do. My new video covers 20, including: The 7½-cent lunch Eleanor Roosevelt served at the White House. It was cheap, nutritious, and bad enough that guests started eating before they showed up. How Seattle neighbors in the 1930s...

Hi Reader, The way your mouse scrolls can help a website identify you. Every mouse moves the page a slightly different number of pixels per notch, and that number stays consistent for your device. Add your screen size, your browser, and a few network settings, and a site can pick you out of a crowd without you ever signing in. That's browser fingerprinting, and it's the subject of this week's episode of Technical Writing Uncensored. My guest is Seth Honda, an English and computer science...