Files
hips/HIPs/hip-0045-documentation-framework-standard.md
zeekayandHanzo Dev ade9bd23b3 Three drafts the estate already implements, and six that it does not
Audited the 21 Draft HIPs against production. Three describe what is running
and become Final:

  0111  every canonical path answers on hanzo.id with the right content type,
        and the eight verb aliases this HIP forbids now return 410 with a
        successor pointer. access_token is 404; token is the only spelling.
        The conformance section said the prohibitions were unmet — that was
        measured in July, the retirement order landed, and it is now wrong in
        the HIP's favour. Also: serverUrl for Hanzo is hanzo.id, not
        iam.hanzo.ai, which serves the SPA catch-all on every path and would
        walk a client straight into the failure this HIP exists to prevent.
  0033  all three tiers answer — 275 first-party images running from GHCR
        under three orgs, Docker Hub mirrors, and oci.hanzo.ai returning 401
        rather than a 404 from a host with nothing behind it.
  0305  the deviation argued for is the one that shipped, and schema.prisma
        cites this HIP by number as the reason.

The rest stay Draft, and six of them say something untrue that had to be
written down before anyone can fix it:

  0018  there is no native PSP. Every fiat ProcessorType is third-party and
        pay.hanzo.ai's default is Square, so payment sovereignty is a mandate
        the code does not implement. Port was 4242; it binds 8090.
  0027  the ownership question this HIP flagged as owed is answered — both
        files in hanzoai/kms now agree it is archived and luxfi/kms is
        canonical. The /api/v1 and /api/v3 surface it documents returns 404.
  0038  Console is not a Langfuse fork. The NOTICE says no Langfuse source is
        used and the first commit is a clean-room build on @hanzo/gui.
  0053  the name belongs to something else now. hanzoai/visor is Hanzo
        Compute, a multi-cloud compute plane with zero Grafana in it.
  0409  Final, and pointing image.repository at an archived repository.
  0002  linking the Jin repo, archived in May, framework never built.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-09 12:32:05 -07:00

31 KiB

hip, title, author, type, category, status, created, requires
hip title author type category status created requires
0045 Documentation Framework Standard Hanzo AI Team Standards Track Interface Final 2026-02-23 HIP-0010

HIP-0045: Documentation Framework Standard

Abstract

This proposal defines the documentation framework standard for the Hanzo ecosystem. All developer-facing documentation sites -- from API references to protocol specifications -- MUST be built using the @hanzo/docs-* package family, a purpose-built fork of the Fumadocs framework extended with multi-brand theming, OpenAPI generation, and cross-ecosystem search.

The framework ships as 24 independently versioned packages in a pnpm monorepo. Applications compose only the packages they need. A single unified wrapper (@hanzo/docs) re-exports everything for convenience.

Repository: github.com/hanzoai/docs Primary Package: @hanzo/docs (unified wrapper) Build Toolchain: tsdown for packages, Turbo for monorepo orchestration Runtime: Next.js 15+ with App Router, React 19+, Tailwind CSS 4+

Design Philosophy

This section explains the why behind each architectural decision. Documentation infrastructure is high-leverage -- the wrong choice here affects every product team and every developer who reads Hanzo docs.

Why Fork Fumadocs (Not Use It Directly)

Fumadocs is the best Next.js documentation framework available. It supports the App Router, React Server Components, and ships with a clean Radix UI component library. It is 40% lighter than Docusaurus and has first-class MDX support.

We forked it because we need capabilities that do not fit upstream's scope:

  • Multi-brand theming: Fumadocs assumes one site = one brand. We need a single deployment pipeline that produces five visually distinct sites from shared content structure. This requires deep changes to the theming layer (CSS variable namespacing, brand-aware component variants, per-site layout configuration).

  • Custom search: Fumadocs provides Orama-based search per site. We need cross-site federated search and integration with our own search API (HIP-1147). This requires changes to the search indexing pipeline and client.

  • OpenAPI generation: While Fumadocs has an OpenAPI plugin, we need tighter integration -- generating pages that match our API playground format, supporting our authentication flows, and rendering response schemas with our type table components.

  • Package renaming: Our fork publishes under the @hanzo/docs-* namespace so that consumers clearly depend on the Hanzo-maintained version, which receives security patches, multi-brand features, and ecosystem integrations that upstream does not.

The fork maintains an upstream remote pointing to fuma-nama/fumadocs. We periodically merge upstream changes and resolve conflicts in our extension points. This gives us upstream improvements (bug fixes, performance, new Radix UI components) while maintaining our custom features.

Trade-off acknowledged: Maintaining a fork requires ongoing merge effort. We accept this because the alternative -- building a docs framework from scratch -- is orders of magnitude more work, and using upstream directly does not meet our multi-brand and OpenAPI requirements.

Why a Monorepo with 24 Packages

Each package is independently versioned and publishable. This matters because:

  • Selective dependency: A site that only needs core source loading and a basic UI does not need to install the OpenAPI generator, Python docgen, or Twoslash TypeScript hints. It installs @hanzo/docs-core + @hanzo/docs-ui and nothing else.

  • Independent release cadence: A bug fix in @hanzo/docs-openapi does not force a release of @hanzo/docs-core. Sites that do not use OpenAPI docs are unaffected.

  • Tree-shaking: Because packages declare explicit exports, bundlers can eliminate unused code. The unified @hanzo/docs wrapper re-exports everything but consumers who import from it still benefit from tree-shaking at the module level.

  • Clear ownership boundaries: Each package has a defined scope. @hanzo/docs-core handles source loading and search. @hanzo/docs-ui handles Radix UI components. @hanzo/docs-openapi handles spec parsing and page generation. Contributors know where to make changes.

Specification

Package Architecture

The framework consists of 24 packages organized by responsibility:

Core Packages

Package NPM Name Purpose
packages/core @hanzo/docs-core Source loading, search indexing, i18n, page tree construction, breadcrumb generation, TOC extraction, syntax highlighting
packages/mdx @hanzo/docs-mdx MDX processing, frontmatter parsing, content collections, file watching, Next.js/Vite integration
packages/hanzo-docs @hanzo/docs Unified wrapper that re-exports all packages under a single import namespace

UI Packages

Package NPM Name Purpose
packages/radix-ui @hanzo/docs-ui Full UI component library built on Radix primitives (sidebar, TOC, breadcrumb, search dialog, code blocks, tabs, cards, callouts)
packages/base-ui @hanzo/docs-base-ui Headless UI components built on @base-ui/react for maximum styling flexibility
packages/tailwind @hanzo/docs-tailwind Tailwind CSS utilities, preset configuration, and CSS custom property definitions
packages/story @hanzo/docs-story Component story/preview system for documentation UI components

Content Generation Packages

Package NPM Name Purpose
packages/openapi @hanzo/docs-openapi Auto-generate endpoint documentation from OpenAPI 3.x specs, with interactive playground
packages/typescript @hanzo/docs-typescript Auto-generate type tables from TypeScript declarations and .d.ts files
packages/python @hanzo/docs-python Python API documentation generation (includes fumapy Python package for docstring extraction)
packages/twoslash @hanzo/docs-twoslash TypeScript code hints and inline type annotations in code blocks
packages/doc-gen @hanzo/docs-docgen Generic documentation generation utilities

Integration Packages

Package NPM Name Purpose
packages/mdx-remote @hanzo/docs-mdx-remote Remote MDX content loading (fetch MDX from URLs or CMS)
packages/mdx-runtime @hanzo/mdx-runtime Runtime MDX compilation for dynamic content
packages/obsidian @hanzo/docs-obsidian Obsidian vault adapter (use Obsidian markdown as docs source)
packages/content-collections @hanzo/docs-content-collections Content Collections integration for type-safe content
packages/press @hanzo/docs-press Minimal setup package for quick documentation sites

Tooling Packages

Package NPM Name Purpose
packages/cli @hanzo/docs-cli CLI for scaffolding new doc sites, customizing components, and running dev tasks
packages/create-app @hanzo/docs-create-app Project scaffolding (pnpm create @hanzo/docs-app)
packages/create-app-versions @hanzo/docs-create-app-versions Version tracking for create-app templates
packages/stf @fumari/stf Upstream schema/transform dependency (kept under original namespace)
packages/org @hanzo/docs-org Organization-level shared utilities

Configuration Packages

Package NPM Name Purpose
packages/tsconfig tsconfig Shared TypeScript configuration (base, Next.js, React library)
packages/eslint-config-custom eslint-config-custom Shared ESLint configuration
packages/shared shared Shared internal utilities and registry

Package Dependency Graph

@hanzo/docs (unified wrapper)
  |
  +-- @hanzo/docs-core .............. source, search, i18n, page tree
  |     |
  |     +-- shiki .................. syntax highlighting
  |     +-- @orama/orama .......... full-text search engine
  |     +-- unified/remark ........ markdown processing pipeline
  |
  +-- @hanzo/docs-mdx .............. MDX processing, collections
  |     |
  |     +-- @mdx-js/mdx ........... MDX compiler
  |     +-- chokidar .............. file watching
  |     +-- esbuild ............... fast JS/TS bundling
  |
  +-- @hanzo/docs-ui ............... Radix UI components
  |     |
  |     +-- @radix-ui/* ........... UI primitives
  |     +-- motion ................ animations
  |     +-- next-themes ........... dark/light mode
  |     +-- tailwind-merge ........ class merging
  |
  +-- @hanzo/docs-openapi .......... OpenAPI doc generation
  |     |
  |     +-- @scalar/openapi-parser . spec parsing
  |     +-- openapi-sampler ....... example generation
  |     +-- react-hook-form ....... playground forms
  |
  +-- @hanzo/docs-typescript ....... TS type tables
  +-- @hanzo/docs-python ........... Python docgen
  +-- @hanzo/docs-twoslash ......... TS code hints
  +-- @hanzo/docs-obsidian ......... Obsidian adapter
  +-- @hanzo/docs-press ............ minimal setup
  +-- @hanzo/docs-cli .............. scaffolding
  +-- @hanzo/docs-mdx-remote ....... remote MDX
  +-- @hanzo/mdx-runtime ........... runtime MDX
  +-- @hanzo/docs-content-collections
  +-- @hanzo/docs-docgen

Sites Powered by This Framework

Site URL App Directory Purpose
Main Docs docs.hanzo.ai apps/docs Primary Hanzo documentation, API reference
HIPs hips.hanzo.ai ../hips/docs Hanzo Improvement Proposals
Zen LM zenlm.org apps/zen-docs Zen model family documentation
ZAP Protocol zap.hanzo.ai apps/zap-docs ZAP protocol specification
Dev Docs dev.hanzo.ai apps/dev-docs Developer guides and tutorials
Bot Docs bot.hanzo.ai apps/bot-docs Bot framework documentation

Source Configuration

Every documentation site MUST define a source.config.ts at its root:

import { defineConfig, defineDocs } from '@hanzo/docs-mdx/config';

export default defineConfig({
  docs: defineDocs({
    dir: 'content/docs',
  }),
});

This file declares the content sources. The MDX package uses it to:

  1. Discover markdown/MDX files in the specified directories
  2. Extract frontmatter metadata
  3. Build the page tree (navigation structure)
  4. Generate TypeScript types for content collections

Source Loader

Each site MUST create a source loader in lib/source.ts:

import { docs } from '@/.source';
import { loader } from '@hanzo/docs-core/source';

export const source = loader({
  baseUrl: '/docs',
  source: docs.toFumadocsSource(),
});

The loader transforms raw content into a structured page tree with:

  • URL slugs derived from file paths
  • Navigation ordering from frontmatter or file naming (01-getting-started.mdx)
  • Folder-based grouping with meta.json for custom ordering
  • Breadcrumb data for each page

Page Component Pattern

Documentation pages follow this pattern:

import { source } from '@/lib/source';
import { DocsPage, DocsBody } from '@hanzo/docs-ui/layouts/docs/page';
import defaultMdxComponents from '@hanzo/docs-ui/mdx';
import { notFound } from 'next/navigation';

export default async function Page(props: { params: Promise<{ slug?: string[] }> }) {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();

  const MDX = page.data.body;

  return (
    <DocsPage toc={page.data.toc}>
      <DocsBody>
        <MDX components={{ ...defaultMdxComponents }} />
      </DocsBody>
    </DocsPage>
  );
}

Layout System

The framework provides four layout variants:

Layout Import Path Use Case
Docs @hanzo/docs-ui/layouts/docs Standard documentation with sidebar navigation
Home @hanzo/docs-ui/layouts/home Landing pages with hero sections and feature grids
Notebook @hanzo/docs-ui/layouts/notebook Notebook-style layout for tutorials
Flux @hanzo/docs-ui/layouts/flux Alternative layout with fluid navigation

Each layout provides a root layout component and a page component:

// app/docs/layout.tsx
import { DocsLayout } from '@hanzo/docs-ui/layouts/docs';
import { source } from '@/lib/source';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <DocsLayout tree={source.pageTree}>
      {children}
    </DocsLayout>
  );
}

Multi-Brand Theming

Each site configures its brand identity through CSS custom properties and layout configuration. The theming system uses three layers:

Layer 1: CSS Custom Properties

/* Brand: Hanzo */
:root {
  --fd-primary: 0 84% 61%;      /* #fd4444 in HSL */
  --fd-background: 0 0% 4%;
  --fd-foreground: 0 0% 98%;
  --fd-muted: 0 0% 15%;
  --fd-accent: 0 84% 61%;
  --fd-border: 0 0% 15%;
  --fd-ring: 0 84% 61%;
}

/* Brand: Zen */
:root {
  --fd-primary: 210 100% 50%;
  --fd-accent: 210 100% 50%;
}

Layer 2: Layout Configuration

<DocsLayout
  tree={source.pageTree}
  nav={{
    title: 'Hanzo Docs',
    url: 'https://docs.hanzo.ai',
  }}
  sidebar={{
    banner: <Logo brand="hanzo" />,
  }}
  links={[
    { text: 'GitHub', url: 'https://github.com/hanzoai' },
    { text: 'Discord', url: 'https://discord.gg/CJCyAsm9Vr' },
  ]}
>

Layer 3: Content Isolation

Each brand's content lives in its own content/ directory. The source loader is configured per-app, so cross-brand content leakage is impossible at the build level.

The framework supports three search backends:

Built-in Search (Orama)

Full-text search using Orama, indexed at build time:

import { source } from '@/lib/source';
import { createSearchAPI } from '@hanzo/docs-core/search/server';

export const { GET } = createSearchAPI('advanced', {
  indexes: source.getPages().map((page) => ({
    title: page.data.title,
    description: page.data.description,
    url: page.url,
    structuredData: page.data.structuredData,
  })),
});

Algolia Adapter

For sites that need hosted search with analytics:

import { createSearchAPI } from '@hanzo/docs-core/search/algolia-server';

export const { GET } = createSearchAPI({
  appId: process.env.ALGOLIA_APP_ID!,
  apiKey: process.env.ALGOLIA_API_KEY!,
  indexName: 'hanzo-docs',
});

Custom Search API

For integration with Hanzo Search (HIP-1147):

import { createSearchAPI } from '@hanzo/docs-core/search/server';

export const { GET } = createSearchAPI('custom', {
  search: async (query) => {
    const results = await fetch(`https://search.hanzo.ai/v1/search?q=${query}`);
    return results.json();
  },
});

Internationalization (i18n)

Built-in i18n support with file-based routing:

content/
  docs/
    index.mdx          # Default language (en)
    index.zh.mdx        # Chinese
    index.ja.mdx        # Japanese

Configuration:

// lib/source.ts
import { loader } from '@hanzo/docs-core/source';
import { i18n } from '@hanzo/docs-core/i18n';

export const { source, openapi } = loader({
  baseUrl: '/docs',
  source: docs.toFumadocsSource(),
  i18n: {
    languages: ['en', 'zh', 'ja'],
    defaultLanguage: 'en',
  },
});

Middleware for locale negotiation:

// middleware.ts
import { createI18nMiddleware } from '@hanzo/docs-core/i18n/middleware';

export default createI18nMiddleware({
  languages: ['en', 'zh', 'ja'],
  defaultLanguage: 'en',
});

MDX Components

The framework provides a standard set of MDX components available in all documentation pages:

Component Description Usage
Callout Info/warning/error callouts <Callout type="warn">Text</Callout>
Card Linked card with title and description <Card title="Guide" href="/docs/guide">
Cards Card grid container <Cards><Card .../><Card .../></Cards>
Tab / Tabs Tabbed content panels <Tabs items={['npm', 'pnpm']}><Tab>...</Tab></Tabs>
Step / Steps Numbered step-by-step guides <Steps><Step>...</Step></Steps>
TypeTable Auto-generated type property tables <TypeTable type={MyInterface} />
Accordion Collapsible content sections <Accordion title="Details">...</Accordion>
Files File tree visualization <Files><File name="app.ts" /><Folder name="lib" /></Files>
ImageZoom Zoomable images <ImageZoom src="/img/arch.png" />
CodeBlock Syntax-highlighted code with copy button Automatic from fenced code blocks
InlineTOC Inline table of contents <InlineTOC />
Banner Announcement banner <Banner>New release!</Banner>

These are registered as default MDX components and available in all .mdx files without explicit imports.

OpenAPI Integration

The @hanzo/docs-openapi package generates documentation pages from OpenAPI 3.x specification files.

Spec Loading

// source.config.ts
import { defineConfig, defineDocs } from '@hanzo/docs-mdx/config';
import { defineOpenAPI } from '@hanzo/docs-openapi';

export default defineConfig({
  docs: defineDocs({ dir: 'content/docs' }),
  openapi: defineOpenAPI({
    input: './openapi-specs/*.yaml',
    output: './content/docs/api',
  }),
});

Generated Output

For each endpoint in the spec, the package generates:

  • Endpoint page: Method, path, description, parameters, request body, response schemas
  • Interactive playground: Try-it-out form with authentication, parameter inputs, and live response
  • Type schemas: Rendered as collapsible property tables with nested object support
  • Code samples: Auto-generated cURL, JavaScript, Python, and Go examples

Scalar Integration

For interactive API exploration, the OpenAPI package integrates with Scalar:

import { createScalarPage } from '@hanzo/docs-openapi/scalar';

export default createScalarPage({
  spec: './openapi-specs/hanzo-api.yaml',
  theme: 'kepler',
});

TypeScript Type Documentation

The @hanzo/docs-typescript package generates type tables from TypeScript declarations:

import { AutoTypeTable } from '@hanzo/docs-typescript/ui';

// Automatically generates a property table from the TypeScript interface
<AutoTypeTable path="./src/types.ts" name="UserConfig" />

This resolves the full type, including inherited properties, generics, and JSDoc comments. The output is a structured table showing property name, type, default value, and description.

Python API Documentation

The @hanzo/docs-python package includes a Python component (fumapy) that extracts docstrings and type annotations:

# Generate Python API docs
uv run fumapy generate --module hanzo.sdk --output content/docs/python-sdk

The generated MDX files include function signatures, parameter tables, return types, and docstring content.

Build Toolchain

Package Building

All packages (except the @hanzo/docs wrapper) use tsdown for compilation:

// packages/core/tsdown.config.ts
import { defineConfig } from 'tsdown';

export default defineConfig({
  entry: ['src/**/*.ts', 'src/**/*.tsx'],
  format: 'esm',
  dts: true,
  clean: true,
});

The @hanzo/docs wrapper uses tsup because it needs special re-export handling.

Monorepo Orchestration

Turbo manages the build graph:

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "out"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

The ^build dependency ensures packages build before the apps that consume them.

Application Building

Documentation apps use Next.js with static export:

// next.config.ts
import { createMDX } from '@hanzo/docs-mdx/next';

const withMDX = createMDX();

export default withMDX({
  output: 'export',     // Static HTML for CDN deployment
  images: { unoptimized: true },
});

Deployment

Documentation sites support three deployment targets:

Sites with server-side features (search API routes, ISR) deploy to Vercel:

# Automatic via GitHub integration
# Or manual:
vercel deploy --prod

Cloudflare Workers (Edge)

For globally distributed static sites with edge functions:

// open-next.config.ts (for Cloudflare adapter)
export default {
  default: {
    override: {
      wrapper: 'cloudflare-node',
      converter: 'edge',
    },
  },
};

Deploy via Wrangler:

pnpm build && wrangler pages deploy out

Static Export (CDN / K8s)

For maximum simplicity, export static HTML and serve from any HTTP server:

pnpm build        # Produces ./out/ directory
# Serve via nginx, Caddy, or S3+CloudFront

The apps/bot-docs and apps/zt-docs sites use this pattern with nginx in a Docker container:

FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN pnpm install && pnpm build

FROM nginx:alpine
COPY --from=builder /app/out /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

App Structure for New Documentation Sites

New documentation sites MUST follow this structure:

apps/my-docs/
  app/
    layout.tsx              # Root layout with DocsLayout
    page.tsx                # Landing page
    docs/
      [[...slug]]/
        page.tsx            # Dynamic docs page
    api/
      search/
        route.ts            # Search API endpoint
  content/
    docs/
      index.mdx             # Docs root page
      getting-started.mdx
      guides/
        meta.json           # Navigation ordering
        installation.mdx
        configuration.mdx
  lib/
    source.ts               # Source loader configuration
  source.config.ts           # Content source definition
  mdx-components.tsx         # MDX component registration
  next.config.ts             # Next.js configuration with MDX
  package.json
  postcss.config.mjs
  tsconfig.json

The @hanzo/docs-cli can scaffold this structure:

npx @hanzo/docs-create-app my-docs

Upstream Sync Process

The fork maintains compatibility with upstream Fumadocs. The sync process:

# 1. Fetch upstream changes
git remote add upstream https://github.com/fuma-nama/fumadocs.git  # one-time
git fetch upstream

# 2. Create merge branch
git checkout -b merge-upstream-YYYY-MM-DD

# 3. Merge upstream dev branch
git merge upstream/dev

# 4. Resolve conflicts (usually in package.json names and brand-specific files)

# 5. Run bulk rename script
bash scripts/mirror-ui-change.sh

# 6. Verify build
pnpm install && pnpm build && pnpm test

# 7. Open PR for review

The scripts/setup-fork.sh script automates creating brand-specific documentation forks for ecosystem partners.

Rename Mapping

During upstream sync, all references are renamed:

Upstream Name Hanzo Name
fumadocs-core @hanzo/docs-core
fumadocs-ui @hanzo/docs-ui
fumadocs-mdx @hanzo/docs-mdx
fumadocs-openapi @hanzo/docs-openapi
fumadocs-typescript @hanzo/docs-typescript
fumadocs-twoslash @hanzo/docs-twoslash
@fumadocs/cli @hanzo/docs-cli
@fumadocs/base-ui @hanzo/docs-base-ui
@fumadocs/story @hanzo/docs-story
@fumadocs/tailwind @hanzo/docs-tailwind
fumadocs-docgen @hanzo/docs-docgen

Note: packages/radix-ui publishes as @hanzo/docs-ui (the primary UI package). The original fumadocs-ui name maps to this package.

Implementation

Repository Structure

github.com/hanzoai/docs/
  .changeset/               # Changeset configuration for versioning
  .github/
    workflows/
      deploy-docs.yml       # Deploy docs.hanzo.ai
      deploy-zen-docs.yml   # Deploy zenlm.org
      deploy-zap-docs.yml   # Deploy zap.hanzo.ai
      deploy-bot-docs.yml   # Deploy bot.hanzo.ai
      lint.yml              # Lint all packages
      test.yml              # Test all packages
      release.yml           # Publish to npm via changesets
  apps/
    docs/                   # docs.hanzo.ai
    zen-docs/               # zenlm.org
    zap-docs/               # zap.hanzo.ai
    bot-docs/               # bot.hanzo.ai
    dev-docs/               # dev.hanzo.ai
    cloud/                  # cloud docs
    flow/                   # flow docs
    zt-docs/                # zt docs
  packages/                 # 24 packages (see Package Architecture)
  examples/                 # 24 example applications
  scripts/
    build-all-docs.sh       # Build all doc sites
    dev-all-docs.sh         # Run all doc sites in dev mode
    mirror-ui-change.sh     # Sync UI changes across radix-ui and base-ui
    setup-fork.sh           # Create branded doc forks
    cf-pages-deploy.mjs     # Cloudflare Pages deployment script
  package.json              # Root workspace configuration
  pnpm-workspace.yaml       # Workspace package declarations
  turbo.json                # Turbo build pipeline configuration
  vitest.config.ts          # Test configuration

Version Management

Packages use Changesets for version management:

# Add a changeset
pnpm changeset

# Version all changed packages
pnpm version

# Publish to npm
pnpm release

The release process:

  1. Developer runs pnpm changeset and selects affected packages
  2. CI runs changeset version to bump versions
  3. CI runs turbo run build --filter=./packages/* to build all packages
  4. CI runs changeset publish to push to npm
  5. Packages with postpublish scripts run any post-publish tasks

Workspace Configuration

# pnpm-workspace.yaml
packages:
  - packages/*
  - apps/*
  - examples/*

All packages, apps, and examples are part of the workspace. Internal dependencies use workspace:* protocol for always-latest linking during development.

CI/CD Workflows

Package Publishing (release.yml)

Triggered on push to main. Uses changesets to determine which packages need publishing:

name: Release
on:
  push:
    branches: [main]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install
      - uses: changesets/action@v1
        with:
          publish: pnpm release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Site Deployment (deploy-*.yml)

Each documentation site has its own deployment workflow. Example for docs.hanzo.ai:

name: Deploy Docs
on:
  push:
    branches: [main]
    paths:
      - 'apps/docs/**'
      - 'packages/**'
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - run: pnpm install
      - run: pnpm build --filter docs
      - uses: cloudflare/pages-deploy-action@v1
        with:
          directory: apps/docs/out
          project-name: hanzo-docs

Compatibility Matrix

Dependency Minimum Version Tested Version
Node.js 18.17.0 20.x, 22.x
Next.js 15.3.0 16.1.x
React 19.2.0 19.2.x
Tailwind CSS 4.0.0 4.1.x
pnpm 10.0.0 10.18.x
TypeScript 5.5.0 5.9.x

Configuration Files

Every documentation app requires these configuration files:

next.config.ts

import { createMDX } from '@hanzo/docs-mdx/next';

const withMDX = createMDX();

export default withMDX({
  output: 'export',
});

postcss.config.mjs

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

mdx-components.tsx

import type { MDXComponents } from 'mdx/types';
import defaultComponents from '@hanzo/docs-ui/mdx';

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...defaultComponents,
    ...components,
  };
}

Security

Content Security

  • No arbitrary code execution: MDX files are compiled at build time, not runtime. User-submitted content cannot execute arbitrary JavaScript.
  • Sanitized HTML: The rehype-raw plugin processes inline HTML through a sanitizer before rendering.
  • No secrets in content: Documentation content MUST NOT contain API keys, tokens, or credentials. Example code MUST use placeholder values (sk-..., your-api-key).

Dependency Security

  • Dependabot enabled: The repository uses Renovate for automated dependency updates.
  • npm provenance: Published packages include npm provenance attestations.
  • Lockfile integrity: The pnpm-lock.yaml is committed and verified in CI.

Deployment Security

  • Static export preferred: Static HTML has no server-side attack surface.
  • CSP headers: All deployed sites MUST include Content Security Policy headers restricting script sources.
  • HTTPS only: All documentation sites are served over HTTPS with HSTS enabled.

Monitoring and Observability

Build Metrics

Metric Description Target
docs.build.duration_seconds Full build time for a documentation site < 120s
docs.package.build_seconds Individual package build time < 30s
docs.bundle.size_kb Client-side JavaScript bundle size < 250KB
docs.pages.count Total pages across all sites Informational
docs.search.index_size_kb Search index size < 5MB per site

Lighthouse Targets

All documentation sites MUST meet these Lighthouse scores:

Category Minimum Score
Performance 90
Accessibility 95
Best Practices 95
SEO 95

Uptime

Documentation sites are monitored via the Hanzo status page. Target uptime: 99.9%.

# 1. Scaffold a new docs site
npx @hanzo/docs-create-app my-docs

# 2. Install dependencies
cd my-docs && pnpm install

# 3. Add content
# Create .mdx files in content/docs/

# 4. Run development server
pnpm dev

# 5. Build for production
pnpm build

Future Work

Phase 4: Automation (Q4 2026)

  • Auto-generate SDK documentation from source code (Go, Python, TypeScript, Rust)
  • Auto-sync API docs when OpenAPI specs change in CI
  • AI-assisted content generation for boilerplate documentation
  • Automated broken link detection and content freshness scoring

References

  1. Fumadocs Documentation -- Upstream framework
  2. Hanzo Docs Repository -- Source code
  3. Next.js App Router Documentation
  4. MDX Documentation
  5. Radix UI Primitives
  6. Orama Search Engine
  7. Changesets Version Management
  8. Turbo Build System
  9. HIP-0010: Model Context Protocol Integration Standards
  10. HIP-1147: Search — Hybrid Retrieval
  11. HIP-0036: CI/CD Build System Standard

Copyright and related rights waived via CC0.