Build Mac AppDocsMenu

Features

The blog: posts, guides and comparisons

MDX files in site/content/blog/, one per post, rendered at /blog/<slug>. The model post is writing-your-first-post.mdx (a draft, so it never ships); /add-blog-post writes new ones in the same shape.

What the site does with a post

SurfaceWhat it shows
/blog/<slug>the answer first, then the body, sources, tags, related posts
/blog/<slug>/opengraph-imagea share card with the title and answer
/blog, /blog/tag/<tag>lists; noindex until MIN_INDEXABLE_ITEMS (3) posts
/authors/<id>the author, their profiles, their posts (site/lib/authors.ts)
JSON-LDBlogPosting (or TechArticle for guides) with the answer as abstract, plus breadcrumbs
/sitemap.xmlevery post; the index and tags once they pass the threshold
/feed.xmlposts and releases, newest first
/llms.txt, /llms-full.txteach post by its answer; the full text with sources
footera Blog link, once there is a published post

Drafts (draft: true) render under pnpm dev only: never in a build, the sitemap or the feed.

The rules, and why

site/lib/blog/index.ts holds them, and a post that breaks one fails the build with the file and the reason:

  • Answer first (answer, one or two sentences). Search results and answer engines lift the first direct answer. A post that makes them read five paragraphs of scene-setting gets someone else quoted.
  • Title at most 60 characters, description at most 155, no price in the description. These are the lengths search results show, and prices live in one file.
  • Hand-written dates. updated moves when the prose changes. It feeds the byline, the JSON-LD dateModified and the sitemap lastModified, so it can never be a clock.
  • Sources with https:// links for every claim a reader might check. They're printed under the post and in llms-full.txt.
  • Comparisons also need checked: (the date the facts about other products were verified) and at least one source. No verdicts: facts, a source for each, the date, and the reader decides.
  • The plain-text mirror (llms-full.txt, search snippets) is generated from the MDX. The test fails a post whose mirror is empty or still carries markup.

Getting found

  • IndexNow. Set INDEXNOW_KEY (8 to 128 letters, digits or hyphens) and deploy. The site then serves /indexnow-key.txt, and after each deploy that publishes or changes posts, run cd site && pnpm indexnow (the whole sitemap) or pnpm indexnow /blog/<slug>. Bing, and through it ChatGPT search, picks the pages up within hours.
  • AI crawlers are allowed (site/app/robots.ts lists them by name). Blocking them is one edit there, with the reasons written beside it.
  • Authors are real people. Fill in site/lib/authors.ts, with profiles that prove the person exists. Engines weigh attributable writing.

This page is docs/blog.md in the repository, copied 2026-09-25.