Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Cargo.toml",
"packages/cloudflare-api-site/src/components/ui/**/*.ts",
"packages/cloudflare-api-site/src/lib/cn.ts",
"packages/cloudflare-api-site/src/styles/globals.css"
"packages/cloudflare-api-site/src/styles/globals.css",
"packages/docs/src/content/**"
]
}
7 changes: 6 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
"ignorePatterns": ["node_modules", "dist", "**/_generated/**", ".wrangler"],
"overrides": [
{
"files": ["packages/astro-fern/**", "packages/cloudflare-api-site/**", "packages/fern-forge/**"],
"files": [
"packages/astro-fern/**",
"packages/cloudflare-api-site/**",
"packages/docs/**",
"packages/fern-forge/**"
],
"rules": {
"curly": "off"
}
Expand Down
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ API documentation site for Forge OpenAPI specs, built on Astro.
- **`packages/astro-fern`**: Generic Astro engine for rendering Fern-based API documentation.
- **`packages/fern-forge`**: `astro-fern` extension that validates and adapts Forge OpenAPI metadata.
- **`packages/docs-site`**: API documentation website consuming `astro-fern` and `fern-forge`. The OpenAPI spec is fetched from the `openapi.forge.json` GitHub release asset (or a local file via `FORGE_OPENAPI_SPEC`).
- **`packages/docs`**: The documentation site for Forge itself (the generator, its model and its plugins), built with Astro and Nimbus. `packages/docs/AGENTS.md` has its rules.

## Conventions

- **Docs move with the code**: Before finishing any change, check `packages/docs` for every page it affects and update them in the same change. That includes the CLI, the model and its Rust, TypeScript and WIT APIs, OpenAPI rules, extensions, error messages, the built-in targets, and `forge-plugin`. Examples and output on the pages are real, so rerun them rather than editing by hand. `packages/docs/AGENTS.md` has the rules for writing pages.
- **Open Source Separation**: Generic packages (`astro-fern`, `fern-forge`) must remain free of Cloudflare-specific dependencies.
- **Formatting & Linting**: `oxfmt` and `oxlint`, configured only at the root (`.oxfmtrc.json`, `.oxlintrc.json`). `pnpm check` verifies; `pnpm format` rewrites.
- **Type Checking**: Strict TypeScript compiler settings across all packages via `pnpm typecheck`.
Expand All @@ -30,6 +32,9 @@ pnpm typecheck
# Run all unit tests
pnpm test

# Build the docs site
# Build the API documentation site
pnpm --filter docs-site build

# Build the Forge docs site
pnpm --filter forge-docs build
```
17 changes: 17 additions & 0 deletions packages/docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# build output
dist/
# generated types
.astro/
# nimbus build scratch: materialized lint config and the route manifest.
# `nimbus.json` next to it is the opposite -- hand-owned, and committed.
.nimbus/
# wrangler local state
.wrangler/
# dependencies
node_modules/
# environment variables
.env
.env.production
.dev.vars
# pagefind writes its index into dist/, but leaves a cache here
.pagefind/
122 changes: 122 additions & 0 deletions packages/docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# The Forge docs site

Astro, with [Nimbus](https://nimbus-docs.com) (`@cloudflare/nimbus-docs`) as the docs framework. The
package handles content schemas, sidebar and TOC, MDX to markdown, search, OG cards, `llms.txt`,
build hooks, and the `nimbus-docs` CLI. Everything in `src/` is a real file in this repo and yours to
edit, including the files the scaffold wrote.

`README.md` next to this file explains how the site looks and why.

## Working in here

This package is part of the repo pnpm workspace. Install once at the repo root:

```sh
pnpm install
pnpm --filter forge-docs dev # http://localhost:4321
pnpm --filter forge-docs build # static output in ./dist
pnpm --filter forge-docs check # astro check: types, content collections
pnpm --filter forge-docs lint:docs
```

`wrangler.jsonc` serves `dist/` as static assets on a Worker, with no script. It has no account or
route yet.

## File layout

```text
astro.config.ts # nimbus(defineNimbusConfig({...})): sidebar, lint rules, markdown plugins
nimbus.json # what the scaffold and the registry installed. Committed.
.nimbus/ # build scratch. Gitignored.
fonts/ # build-time only, for the OG cards. Not under public/ on purpose.
og-assets/ # the mark drawn on OG cards
src/
├── components.ts # MDX globals registry: every component used in .mdx must be listed
├── components/ # ours: Hero, PipelineFigure, Features, NavList, Logo, Header, Prose
│ └── ui/<slug>/ # from the Nimbus registry
├── content/docs/**/*.mdx # the pages, one directory per sidebar group
├── content/partials/ # partials for <Render file="..." />; none yet
├── content.config.ts
├── layouts/ # BaseLayout (head, theme bootstrap), DocsLayout (three columns)
├── lib/ # cn.ts
├── pages/ # [...slug].astro, 404, llms.txt, robots.txt, og/
└── styles/ # globals.css (tokens and shell), prose.css
public/ # favicon, _headers
wrangler.jsonc
```

## Writing docs

Frontmatter validates against Nimbus's `docsSchema`. `title` is required. Sidebar groups are declared
in `astro.config.ts`; position within a group comes from `sidebar.order`:

```mdx
---
title: My page
description: One-line summary.
sidebar:
order: 3
---

Content here. The H1 comes from `title`; don't repeat it in the body.
```

Rules:

- **Every claim is checked against the source.** The pages describe Forge's behaviour precisely:
which errors, which order, which defaults. Read the Rust doc comments (`src/lib.rs`,
`src/types.rs`, `src/method.rs`, `src/link.rs`) or run `forge` on a small document before writing
one. Output shown on a page is real output.
- **Every internal link must resolve.** `nimbus/internal-link` is an error, so a broken link fails
the build. It does not check `#anchors`; check those against the built HTML.
- **Quote a `description` that contains `: `.** YAML reads it as a mapping otherwise, and the build
fails.
- **Components must be PascalCase and registered in `src/components.ts`.**
- **Partials use `<Render file="..." />`.** Don't import `.mdx` directly.
- **A `mode: custom` page gets a bare `<main>`**, so its prose must be wrapped in `<Prose>`.
- **Don't remove `<AgentDirective />` from `BaseLayout.astro`.** It points agents at `/llms.txt`.

- **Other generators live under Compatibility Modes.** Forge's own conventions (methods named by a
dotted `operationId`, models by schema name, fields by wire name) are what every page describes.
Extensions that Forge reads for compatibility with another generator are described only on that
generator's page in `src/content/docs/compatibility/`, and no other page, component or file in
this package names that generator. Elsewhere, say "a compatibility mode" and point at the sidebar
group. Check with a case-insensitive grep for the generator's name before finishing.

House style: no em dashes, and no `--` either, since it renders as two hyphens; every code fence
gets a language; no code block directly under a heading, so say what it is first. Plugins are
first-class: when a page describes a built-in target, say that it is a plugin like any other.

## Public content

This site is public. Never mention internal repositories, hosts, tickets or links in it. Describe
internal work in generic terms.

## Adding things

| Goal | Action |
| -------------------- | ------------------------------------------------------------------------------------------- |
| New doc page | `src/content/docs/<group>/<slug>.mdx`, with `sidebar.order`. The group autogenerates. |
| New sidebar group | A directory under `src/content/docs/` and an entry in `astro.config.ts`. |
| UI from the registry | `pnpm exec nimbus-docs add <slug>`, then register it in `src/components.ts` if MDX uses it. |
| OG card restyle | `src/pages/og/_og-card-config.ts`. |
| Check it builds | `pnpm exec nimbus-docs check --json`, then a build for link checking. |

Two registry components are modified, so `add --overwrite` will undo the changes:
`page-actions/PageActions.astro` (a `data-pagefind-ignore` on the actions, a fixed locale and time
zone for the "Updated" date, and the divider at `/70`, which keeps it above 3:1 in both schemes) and
`breadcrumbs/Breadcrumbs.astro` (separators that inherit `text-muted-foreground`, for contrast).

## Don't

- Spend the orange accent on anything but calls to action and the active state. Prose links are
ink.
- Darken or theme-swap `--fg-orange`. It is Cloudflare orange, `#f6821f`, on both schemes. For
orange text on a light background, use `--fg-orange-text`, which is readable.
- Dim text with `opacity`, or Tailwind's alpha modifier. `--nb-muted-foreground` is the measured
secondary colour. The page-actions divider is the one measured exception.
- Recolour the logo. Its two oranges are the Cloudflare mark's own, in `Logo.astro`, the favicon and
`og-assets/`.
- Hand-add a component under `src/components/ui/` that the registry has. Use `nimbus-docs add`.
- Attach remark or rehype plugins via `mdx({ remarkPlugins })`: they are silently dropped. Markdown
transformations go in `markdown.mdastPlugins` and `hastPlugins`.
36 changes: 36 additions & 0 deletions packages/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Forge docs

The documentation site for Forge, built with Astro and [Nimbus](https://nimbus-docs.com).

```sh
pnpm install # at the repository root
pnpm --filter forge-docs dev # http://localhost:4321
pnpm --filter forge-docs build # static output in ./dist
```

## How it looks, and why

- **Cloudflare's palette, quietly.** Neutral greys carry the page. Cloudflare orange, `#f6821f`
(`--fg-orange`), is spent on calls to action and the active state, and nothing else, so it keeps
meaning "here". Orange text on light backgrounds uses `--fg-orange-text`, a darker orange, because
the brand orange on white is too faint to read as text.
- **Both schemes are first-class.** The site follows the system setting and the toggle. Every token
has a light and a dark value in `src/styles/globals.css`.
- **The logo is Cloudflare's mark**, in its own two oranges, in `src/components/Logo.astro`, the
favicon, and the OG card mark in `og-assets/`.
- **Inter and JetBrains Mono**, self-hosted through Fontsource, so there are no font requests to a
third party.
- **The landing figure is the argument.** `PipelineFigure.astro` shows the three stages (document,
model, plugins) because that is what Forge is. It is markup, not an image, so it is searchable,
selectable and themed.

## Content

Pages are in `src/content/docs/`, one directory per sidebar group: start, concepts, plugins,
targets, openapi, guides, reference. `AGENTS.md` has the rules for writing them; the most important
is that every statement about Forge is checked against its source or its output.

## Deployment

`wrangler.jsonc` serves `dist/` as static assets. It has no account or route yet; add both when the
site has a home, and build with `DOCS_SITE_URL` set to its origin.
77 changes: 77 additions & 0 deletions packages/docs/astro.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import nimbus, { defineConfig as defineNimbusConfig } from '@cloudflare/nimbus-docs';
import { tableScroll } from '@cloudflare/nimbus-docs/markdown';

const REPO = 'https://github.com/cloudflare/forge';

const nimbusConfig = defineNimbusConfig({
// Nimbus requires a canonical origin: it drives canonical URLs, the absolute OG image URLs,
// robots.txt, the sitemap and the links inside /llms.txt. Set `DOCS_SITE_URL` for any build that
// is deployed; the fallback is only good for local work.
site: process.env.DOCS_SITE_URL ?? 'http://localhost:4321',
title: 'Forge',
description:
'A pluggable, schema-first code generator. Forge reads an OpenAPI document into one typed model and hands it to plugins that write SDKs, CLIs, MCP servers and docs.',
locale: 'en',
github: REPO,
editPattern: `${REPO}/edit/main/packages/docs/{path}`,
socialImageAlt: 'Forge documentation',
// Browser chrome follows the scheme. Dark is the answer to "no preference"; BaseLayout's bootstrap
// reconciles these once it has resolved the mode.
head: [
{
tag: 'meta',
attrs: { name: 'theme-color', content: '#ffffff', media: '(prefers-color-scheme: light)' },
},
{
tag: 'meta',
attrs: { name: 'theme-color', content: '#0d0d0d', media: '(prefers-color-scheme: dark)' },
},
],
// Groups follow the reading order of the project, not the directory tree. `sidebar.order` in each
// page's frontmatter decides its position within its group.
sidebar: {
items: [
{ label: 'Start Here', autogenerate: { directory: 'start' } },
{ label: 'Core Concepts', autogenerate: { directory: 'concepts' } },
{ label: 'Writing Plugins', autogenerate: { directory: 'plugins' } },
{ label: 'Targets', autogenerate: { directory: 'targets' } },
{ label: 'Authoring OpenAPI', autogenerate: { directory: 'openapi' } },
{ label: 'Compatibility Modes', autogenerate: { directory: 'compatibility' } },
{ label: 'Guides', autogenerate: { directory: 'guides' } },
{
label: 'Reference',
items: [{ autogenerate: { directory: 'reference' } }, { label: 'Releases', link: `${REPO}/releases` }],
},
],
},
});

export default defineConfig({
output: 'static',
// Tailwind v4 through its Vite plugin, which is what Astro 7 wants.
vite: {
plugins: [tailwindcss()],
},
// Pull the next page into the HTTP cache while the pointer rests on its link. Paired with the
// cache policy in `public/_headers`, without which a prefetched page cannot be reused.
prefetch: {
prefetchAll: true,
defaultStrategy: 'hover',
},
integrations: [
nimbus(nimbusConfig, {
// Frontmatter has to validate for a page to render, and a broken internal link is a 404 for a
// reader; both are build failures rather than warnings.
rules: {
'nimbus/frontmatter-shape': 'error',
'nimbus/internal-link': 'error',
},
markdown: {
// Wide tables scroll instead of overflowing the measure.
hastPlugins: [tableScroll()],
},
}),
],
});
Binary file added packages/docs/fonts/Inter-Bold.ttf
Binary file not shown.
24 changes: 24 additions & 0 deletions packages/docs/nimbus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "https://nimbus-docs.com/schema/nimbus.json",
"version": "0.6.5",
"lastReviewedNimbusVersion": "0.18.0",
"templatesTag": "templates-v0.6.5",
"variant": "empty",
"registry": "https://nimbus-docs.com/registry",
"install": {
"root": "src",
"aliases": {
"@/*": "src/*"
}
},
"components": [
{
"slug": "link-card",
"type": "registry:ui",
"version": "0.8.2",
"source": "https://nimbus-docs.com/registry",
"hash": "sha256:50a1a703d1111aff309a92256dda1d8dbcb10ba92afd3ff8d4b2a92ac8aab069",
"files": ["src/components/ui/link-card/LinkCard.astro", "src/components/ui/link-card/index.ts"]
}
]
}
Binary file added packages/docs/og-assets/og-mark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions packages/docs/og-assets/og-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "forge-docs",
"version": "0.0.0",
"private": true,
"description": "Documentation website for Forge.",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/cloudflare/forge",
"directory": "packages/docs"
},
"type": "module",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"check": "astro check",
"typecheck": "astro check",
"lint:docs": "nimbus-docs lint",
"lint:docs:fix": "nimbus-docs lint --fix",
"astro": "astro"
},
"dependencies": {
"@cloudflare/nimbus-docs": "^0.18.0",
"@fontsource-variable/inter": "5.3.0",
"@fontsource-variable/jetbrains-mono": "5.3.0",
"@iconify-json/ph": "^1.2.2",
"astro": "^7.2.8",
"astro-og-canvas": "^0.13.0",
"canvaskit-wasm": "^0.41.1",
"clsx": "^2.1.1",
"tailwind-merge": "^3.7.0"
},
"devDependencies": {
"@astrojs/check": "^0.9.10",
"@tailwindcss/vite": "^4.3.3",
"pagefind": "^1.5.2",
"tailwindcss": "^4.3.3",
"typescript": "^6.0.3",
"wrangler": "^4.127.0"
}
}
Loading
Loading