The write-post Skill
Walkthrough of publishing a new blog post with correct front matter and SEO structure.
write-post publishes a new blog post the same way this docs site itself is built: a markdown file
with front matter, no database table, no admin UI. The full front-matter reference lives at
Writing a Blog Post; this page is the skill's own
step-by-step, including the structural choices that decide whether a post actually gets cited by an
AI assistant.
What the app already handles
Once the file exists, you don't write any of the following by hand: the canonical URL, Open Graph
and Twitter tags, BlogPosting structured data, breadcrumbs, the sitemap entry, both feeds, the
llms.txt listing, or the raw-markdown alternate at /blog/<slug>.md. All of it reads from the
file you write.
The steps
- Pick the slug and confirm the gap. The filename is the URL:
content/posts/<slug>.mdserves at/blog/<slug>. Keep it short, lowercase, hyphenated, and stable, since changing it later breaks every inbound link. Don't name a posttags; that path is reserved for the tag index. - Write the front matter.
title,description, andpub_dateare required.descriptiondoes real work: it's the meta description, the social card text, the feed summary, and the line under the search result, all from one sentence. Addtags(each generates a/blog/tags/<tag>page), andcta_*fields only if this post needs a call to action different from the site-wide default. - Structure it so it can be quoted. This is the part that decides whether an assistant cites
the post. The title is the question, phrased the way someone actually types it. The first
sentence of the body restates that question. A direct, concrete answer, a number, a list of
names, a yes with its condition, lands within the first 80 words, written to be lifted out and
shown with no surrounding context, because that's exactly what happens to it. The long version
follows under
##headings that are near-questions themselves, each making sense read alone. Prefer specifics to adjectives, and state limits honestly: hedged, qualified claims get cited more, not less. - Match the house voice. Plain, concrete, and agent-neutral. No em dashes anywhere in copy or
metadata; a spec enforces this, so use a colon, a comma, or a full stop instead. Body headings
start at
##, never#, since the#level renders from the front-matter title. - Link internally, both directions. Link the new post to two or three existing ones, and add a link back to it from the most closely related existing post. An orphan post ranks badly and gets crawled late.
- Check it renders.
bin/dev, then open/blog/<slug>and confirm code blocks highlight, the CTA is right, and the post shows up in/sitemap.xml,/feed.xml, and/llms.txt. - Verify:
bin/checkgreen.
Notes
Set draft: true to keep a work in progress out of the index, the feeds, and the sitemap
entirely. Raw HTML in a post is sanitized on purpose, so a <script> tag is dropped; widen the
allowlist in app/services/markdown_renderer.rb if a post genuinely needs a tag it currently
strips. Posts are baked into the deploy image, so publishing one means committing and deploying, not
just saving a draft somewhere.
Next
See how to phrase a request so Claude Code reaches for the right skill on its own: Prompting Patterns.