Writing blog posts and changelog entries
The frontmatter every blog post and changelog entry must carry, the categories and tag limits, what the editorial validator checks, and how a post ships.
Updated
Posts and changelog entries are MDX files in the repository. A file with valid frontmatter is the whole publishing step: the build reads it, the sitemap and RSS feed pick it up, and the page renders it. This page is the schema.
Blog posts: content/blog/<slug>.mdx
---
title: 'A reliable agent boundary'
category: engineering # engineering | product | customers | thinking
author: editorial # a slug from content/authors
publishedAt: '2026-07-30'
updatedAt: '2026-07-31' # optional, must not precede publishedAt
excerpt: 'What changed and what remains bounded.'
tags: # optional, up to 8, no duplicates
- voice agents
- healthcare operations
draft: false
---
Rules the schema enforces:
title,excerpt,authorare required;categorymust be one of the four.- Dates are
YYYY-MM-DDand must be real dates. tags: at most 8, each 1 to 60 characters, no duplicates. Tags render as a pill row in the post footer and feed the page'skeywordsandog:tags.draft: truehides the post from the index, the feed, the sitemap, and the route.
The filename is the slug and must be lowercase kebab-case. The excerpt is the meta description; the editorial validator enforces 70 to 160 characters on it.
Changelog entries: content/changelog/<slug>.mdx
---
title: 'Regional privacy controls'
publishedAt: '2026-08-07'
summary: 'One sentence on what changed and why it matters.'
tags: # optional, up to 4
- Platform
draft: false
---
The body is a short bullet list. Entries render newest first on /changelog and in its RSS feed.
Docs: content/docs/<slug>.mdx
Same shape as this page: title (60 characters or fewer), description (120 to 155 characters, it is the meta description), track (product or engineering), order (unique within the track), updatedAt. Start the body at ##; the page owns the h1.
What the editorial validator checks
Daily editorial posts pass through scripts/editorial/validate.mjs before they can be published. It rejects a draft that:
- makes an internal product claim not listed in the approved-facts file,
- links to an internal path that is not an allowlisted landing page or an existing post,
- has an excerpt outside 70 to 160 characters.
A new public page must be added to that allowlist in the same PR that ships it, or daily posts cannot link to it.
Writing rules that are not in the schema
- No em dashes. Use a comma, a period, a colon, or parentheses.
- Daily posts are authority content, not keyword pages: no keyword repetition, no word-count targets.
- Comparison or pricing content states the date every price was verified, in paragraph one.
Related
- Design tokens: the type scales the article layout uses.
