Writing Guides
How to write and maintain the Guides, the markdown pages under guides/, and the two sections that share their tooling but not their rules: Upgrading and Blog.
Audience
Of the audiences WarpDrive's documentation serves, guides are written for the ones still learning: technical evaluators deciding whether it fits, hobbyists trying it out, and new engineers picking up a codebase that already uses it. Assume no knowledge of the project's history and none of its concepts until the page introduces them. Existing users arrive too, usually from a search or an API docs link, so cross-link the concepts a page depends on rather than re-explaining them.
Guide Types
Upgrade and migration walkthroughs are not guides; they live in the repo-root upgrading/ directory and follow Upgrading and Blog Pages below.
Guides fall into three types. Keep a single page to a single type; a page that seems to need two is usually two pages.
Tutorial
A tutorial walks the reader through building something specific or completing a task. It must state its prerequisites up front, show complete code at each step, and end with the result the reader should see. Use it when the reader needs to do something, such as setting up a project or wiring up their first request. Of the guide audiences, tutorials narrow to hobbyists and new engineers, who know their own stack but little about WarpDrive, so every step has to be runnable as written. Concept and reference guides keep the full guide audience. Tutorials live in their own top-level Tutorials section (guides/tutorials/), above The Manual, the section holding the concept and reference guides, so a reader can find them without knowing which concept they cover.
Concept
A concept guide explains what something is, why it exists, and how it fits with the rest of WarpDrive. It must define the concept clearly, explain the problem it solves, and cross-link the related concepts and APIs it mentions. Use it when the reader needs to understand something before they can make good decisions about using it, such as how the cache or reactivity works.
Reference
A reference guide organizes the facts about one area so a reader can look something up. It owns the prose-level facts: which options exist, what values they accept, which rules apply and when. It leaves signatures and per-member details to the generated API Docs and links to them rather than restating them. Use it when the reader already knows what they want and needs the details.
Linking to the API Docs
The first time a guide names an exported API in prose, such as useRecommendedStore, findRecord or CachePolicy, link its page in the API Docs with a root-relative URL copied from the rendered page, such as [findRecord](/api/@warp-drive/utilities/json-api/functions/findRecord). Code blocks don't need links, but a symbol a reader needs to look up should be linked in the prose around them. The API docs link back: each symbol's doc comment links the guide that teaches it, and each package's landing page lists its guides, as Link the Guide That Teaches It describes.
Where Files Live
Guides are markdown files under guides/. Add a new page's slug to the items list in its directory's _meta.json so it sorts where you intend; the keys, draft behavior, sidebar, and preview are covered in How the Docs Site Is Built.
Frontmatter and Agent-Only Content
Every page is also published as plain Markdown for coding agents and, unless it is a draft, indexed in llms.txt (see LLM Optimized Documentation). Four things in the source affect what those agents get:
- An
#heading at the top. Start every page with one H1 naming it. It is the page's title in the browser tab, the outline, andllms.txt; a page that opens with##, prose, or a:::callout is listed there asUntitled, and its tab reads only "WarpDrive". The sidebar label comes from_meta.jsonor the file name instead, so a page can look fine in the sidebar and still have no title. descriptionin the frontmatter. Thellms.txtentry for a page is its title alone unless the frontmatter setsdescription, in which case the entry reads- [Title](url): description. An agent choosing which of 900 pages to fetch has only that line to go on, so give every new page a one-sentencedescriptionthat says what a reader can do after reading it, and add one to any page you touch that lacks it.legacy: truein the frontmatter. Set it on a page underguides/,upgrading/orblog/that is only about a legacy setup, such as Models, Adapters or the pre-unification packages. The page moves out ofllms.txtandllms-full.txtintollms-legacy.txtandllms-legacy-full.txt, and the website shows a Legacy badge and a warning at its top. The warning's second sentence defaults to pointing at the current guides; setlegacyAdviceto markdown naming the modern equivalent instead, with root-relative links. Itsllms-legacy.txtentry is titled the same wayllms.txtwould title it. A draft legacy page gets no badge. Don't flag a page that mixes modern and legacy content, or one about LegacyMode, which is a current, recommended schema mode rather than a legacy setup.<llm-only>and<llm-exclude>tags. Content wrapped in<llm-only>appears only in the Markdown outputs, never on the website;<llm-exclude>is the reverse. Use<llm-only>for an instruction that only makes sense to an agent ("always pair this with the schema from the previous section") and<llm-exclude>for a screenshot walkthrough or a "click here" aside. Both are rare; a page that reads well to a human usually reads well to an agent.
Callouts (:::tip) and :::tabs reach agents in their raw form, so write the tab labels and callout titles as if they will be read as plain text.
Upgrading and Blog Pages
Upgrading and Blog are different from the rest of the guides: they hold point-in-time content whose URLs are a permanent contract with readers, not just the current best explanation of a concept. Follow these rules when adding to either section.
These pages are for existing users. An upgrade guide may presume knowledge of the concepts being replaced but never of the ones replacing them. A blog post should say near the top who it is for. LLMs and coding agents also land on these pages, years later and out of order, and will present whatever they find as current unless the page's version and date say otherwise; that is the reason for the dating rule below.
URLs are never renamed or unpublished
Once a page under upgrading/ or blog/ is published, its path doesn't change and the page is never deleted, even after its content is out of date.
If a page's content is fully superseded (a newer major-version guide replaces it, a post is factually wrong, etc.), don't delete or move it. Instead:
Replace its body with a short pointer to the replacement, wrapped in a
:::dangercallout. Keep the frontmattertitleand the<SinceBadge>line so the page still says what it was:md:::danger **We've moved!** This guide has [moved](/upgrading/v6/index.md) :::Add
draft: trueto its frontmatter. This hides the page from the sidebar and nav while leaving it published at its original URL (see Sidebar and_meta.json). Drafts, including a page in adraftdirectory, stay out of the llms files, though each keeps its.mdtwin.
Every page is dated and versioned
Record the WarpDrive* version and the date a page was written for near the top of the page, as a <SinceBadge> followed by the date (YYYY-MM-DD) it was authored or last meaningfully revised:
<SinceBadge version="5.0.0" /> authored 2023-06-10This lets a reader who lands on an old search result or bookmark know immediately whether the page still applies to the version they're using.
A blog post also sets the date it was published as a frontmatter date, written YYYY-MM-DD. The blog's RSS feed (/blog/feed.xml), the Blog page, and each major version's page list every published post that isn't a draft or a section index.md, newest first, and use date to order and date them, so the docs build fails on a post without one:
---
title: Introducing Upgrading & Blog
description: Learn why WarpDrive 5.10 added the permanent Upgrading and Blog sections.
date: 2026-09-05
---A post's feed entry uses its frontmatter title (or its H1) and description. Its link is also its ID in feed readers, which is one more reason a post's URL must never change: renaming it would show subscribers the post a second time as new.
Organize by major version
Each section is sub-divided by major version (upgrading/v5/, blog/v5/, upgrading/v6/, ...). Within a major version's directory:
upgrading/<major>/holds that version's upgrade guide plus any deprecation or feature-specific migration guides written against it.blog/<major>/holds posts published while that major version was current.
Add new major-version directories to the section's root _meta.json items list so they sort in release order rather than alphabetically.