Skip to content

Philosophy

Some of the opinions behind Nimbus, what we believe documentation should look like in a world where humans and agents are both creators and consumers.

Updated View as Markdown
For humans

You own all your code

Layouts, components, content, styles — every visible piece of your site lives in your repo. The scaffolder writes them once and steps back. From there, the project is yours: edit any file, restructure any directory, change any default. No upstream API to wait on, no opinionated theme to fork around.

Coding agents work the same way you do. When nothing important hides behind an import boundary, an agent can reason about the repo far better.

  • my-docs/
    • src/
      • components/
      • content/docs/
      • layouts/
      • pages/
      • styles/
        • globals.css
      • components.ts
    • astro.config.ts
    • package.json

Interactive content, fully yours

Documentation worth reading often needs to show mechanism — how a request flows, how state nests, where a wire docks. Either you adopt a pre-styled component library and inherit its look, or you build the interactive bits from scratch. Nimbus splits the problem.

nimbus-docs/react ships a headless <Diagram> wrapper plus composable hooks — usePhase, useMeasure, useTabIndicator, useDiagram. The wrapper owns the things that are tedious to get right: off-screen pausing, reduced-motion respect, keyboard shortcuts, error boundaries, cross-island coordination. It renders nothing visible itself.

<Diagram>
useDiagram
useTabIndicator
DiagramControls
useMeasure
Tabs

The smallest meaningful example — usePhase walks two steps, the rendered nodes light up in turn. <DiagramControls> is installed via the registry; everything else comes from nimbus-docs/react.

Left
Right
import { Diagram, usePhase } from "@cloudflare/nimbus-docs/react";
import { DiagramControls } from "@/components/react/diagram";

function PingPong() {
  const { current } = usePhase({
    steps: [{ id: "left", hold: 1500 }, { id: "right", hold: 1500 }],
    loop: true,
  });
  return (
    <div className="flex items-center justify-center gap-12 py-12">
      <Node label="Left" active={current === "left"} />
      <Node label="Right" active={current === "right"} />
    </div>
  );
}

export function Demo() {
  return (
    <Diagram label="Ping-pong">
      <DiagramControls />
      <PingPong />
    </Diagram>
  );
}

Action bars, tabs, and play/pause controls install on demand into src/components/react/diagram/ — edit, restyle, or replace freely; the hooks keep working. Sites that never author an interactive card pay nothing.

Human and agent first

Documentation is no longer read only by people, and as a result every Nimbus site ships several machine-readable formats alongside the HTML:

  • A Markdown version of every page at /<slug>/index.md
  • A site-level index at /llms.txt, naming every page
  • JSON-LD in every page’s head, giving search and agent tools enough structured data to recognise what they’re looking at
# Nimbus

A way to build documentation sites on top of Astro.

## Pages
- [Getting started](https://nimbus-docs.com/get-started/index.md)
- [Installation](https://nimbus-docs.com/installation/index.md)
- [CLI](https://nimbus-docs.com/cli/index.md)

These formats are defaults, not add-ons. The cost of being a dead end on the agent web is real, and it grows.

Agentic authoring

Adding Nimbus default components or features is done with nimbus-docs add. It works differently depending on what you’re adding. Components and utilities copy as files — registry:ui and registry:lib slugs resolve their dependencies and land in your repo. Features hand off as prompts — a registry:feature slug is a markdown recipe the coding agent in your environment reads, adapts to your project, and applies.

npx @cloudflare/nimbus-docs add 404-page

The split between the two modes is the one question that matters: which kind of change actually wants a coding agent in the loop, and which is better as a file copy.

Authoring quality is first-class

A docs site whose content drifts in quality undermines its own product. Nimbus treats authoring quality the way a code linter treats source — a layered set of validators, each catching a different class of mistake.

Pre-build validators run automatically and gate the build only when the issue would actually break the site:

  • Config validation — defineConfig is checked for shape and required fields; errors echo the offending value back to you
  • Frontmatter schema validation — Zod-typed schemas catch missing or malformed fields per collection, with editor-friendly error messages
  • MDX component validation — a pre-build content pass catches lowercase usages, unregistered components, and missing imports
  • Registry validation — src/components.ts is parsed and checked against actual MDX usage at build time

The lint engine adds an on-demand authoring-quality layer. Rules have stable identifiers like nimbus/single-h1 and nimbus/bare-url, configured in astro.config.ts alongside the rest of your Nimbus integration. Run nimbus-docs lint for human output, --format json for diagnostics an agent can read, --fix to apply auto-fixes. The build is never gated by lint findings — drafts still render, warnings stay loud but unblocking.

astro.config.tsts
import { defineConfig } from "astro/config";

export default defineConfig({
  integrations: [
    nimbus(nimbusConfig, {
      rules: {
        "nimbus/single-h1": "error",
        "nimbus/bare-url": "warn",
      },
    }),
  ],
});

Component-prop validation against TypeScript signatures lands post-v1.

Readable is the floor

Every Nimbus site already ships the formats agents read — a Markdown version of each page, an llms.txt index, and structured data in the head. A year ago that set a docs tool apart; today it’s table stakes. The interesting line sits further out.

Everyone made docs readable by agents. Nimbus makes docs writable, maintainable, and operable by them — end to end, on a codebase you fully own.

The precondition is the first principle on this page. When every file lives in your repo and nothing important hides behind an import boundary, an agent can do more than read your docs — it can change them safely, because it can see the whole of what it’s touching. A vendor’s themed runtime can be scraped by an agent; it can’t be rewritten by one.

That’s why features arrive as recipes rather than code you wire up by hand. nimbus-docs add detects when it’s running inside a coding agent and pipes it a structured recipe — discover the project, confirm a plan, execute, then verify the build still passes and check whether the feature was already installed before touching a file. Installation stops being a copy-paste chore and becomes a conversation your agent owns from start to finish.

# inside a coding agent, the recipe pipes straight in
npx @cloudflare/nimbus-docs add new-version
# from a human shell, hand it to the agent of your choice
npx @cloudflare/nimbus-docs add new-version --print | claude

Provenance is a primitive

The moment agents start drafting pages, the question stops being can a machine read this and becomes who wrote this, and has a human checked it. Because you own the content collections, the answer lives in the schema you control — provenance is a few schemaFields away, not a convention bolted on top.

The starter ships one such field. The default is inverted: agent-facing is assumed, so audience: "human" is the deliberate flag for a page written first for people. You extend the schema with more the same way — this site adds aiGenerated to mark a page an agent drafted but no human has reviewed yet, and the page-actions row surfaces an “awaiting review” label until someone signs off:

src/content.config.tsts
import { z } from "astro/zod";

docsCollection({
  schemaFields: {
    audience: z.literal("human").optional(),
    aiGenerated: z.boolean().optional(), // shows "awaiting review" until cleared
  },
})

With the field registered, the origin and review state of every page travel with the page itself:

src/content/docs/new-endpoint.mdxyaml
---
title: New endpoint
aiGenerated: true   # drafted by an agent — shows "awaiting review" until a human clears it
---

Provenance only pays off if drift gets caught. The lint engine emits versioned JSON carrying character-precise fixes that --fix applies in place, and the scaffolded AGENT.md ships an audit recipe with a fixed diagnostic format — so an agent can sweep the whole site and report back in a shape another tool can parse:

- [error] src/content/docs/cli.mdx:42 — broken internal link "/instal" — did you mean "/installation"?
- [warn]  src/content/docs/registry.mdx:8 — link text "here" isn't meaningful out of context.
Summary: 1 error, 1 warning.

The docs become something an agent can keep correct over time — maintained and operable, not just published — on a repo that’s yours, not a vendor’s.

The tree is the truth

There is no second config to maintain alongside your content. The directory structure under src/content/ is the URL structure. The directory structure is also the sidebar. Move a file and its entry moves with it; delete a file and the entry disappears. Frontmatter handles the fine-grain knobs — order, badges, draft state — but the shape of the tree comes from the filesystem itself.

  • src/content/docs/
    • getting-started.mdx
    • guides/
      • styling.mdx
      • deploying.mdx
    • reference/
      • api.mdx

The result is a single source of truth for what pages exist. The site can’t drift from its own contents, because its contents are the site.

Versions are just collections

Most docs tools bolt versioning on as a special case — parallel filesystems, URL rewrites, custom routing. Nimbus does it with a primitive it already has: multi-collection content.

Each version is its own content collection, with the same schema. A docs-v2/ collection is a v2 site; a docs-v3/ collection is v3. Routes and sidebars pick up each version independently. The version picker is a thin layer on top.

  • src/content/
    • docs/
    • docs-v2/
    • docs-v3/

The same primitive handles internationalisation (a docs-fr/ collection is a French site) and per-product splits (a docs-api/ collection sits next to docs-cli/). When you need versions, you already have most of what you need; you didn’t pay for it earlier.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close