Skip to main content

docs

Generate a documentation site from your ADRs and specs. Use when the user says "generate docs", "create a docs site", or wants to publish their architecture decisions.

Governing Artifacts​

ADR-0016 · SPEC-0014

Usage​

/sdd:docs [project name or options] [--module <name>]
Required Tools
  • Bash
  • Read
  • Write
  • Edit
  • Glob
  • Grep
  • Task
  • AskUserQuestion

Overview​

Harness portability. This skill runs on any agent harness that loads Agent Skills — Claude Code, Codex CLI, OpenCode, Crush. Tool names used below (AskUserQuestion, Task, TeamCreate, SendMessage, TaskCreate, ToolSearch, mcp__*, $\{CLAUDE_PLUGIN_ROOT\}) denote capabilities, not hard requirements: map each to your harness's equivalent or use the documented fallback per $\{CLAUDE_PLUGIN_ROOT\}/references/harness-compat.md. References to CLAUDE.md mean the project memory file (CLAUDE.md, AGENTS.md, or CRUSH.md) per harness-compat § "Project Memory File". A citation of the form shared-patterns.md § "Section" names one ## heading in that file — load only that section (see its "How to Read This File" note), never the whole file.

Transform ADRs and OpenSpec specs (located via the Artifact Path Resolution pattern from $\{CLAUDE_PLUGIN_ROOT\}/references/shared-patterns.md § "Artifact Path Resolution") into a polished documentation website with:

  • RFC 2119 keyword highlighting (MUST, SHALL, MAY, etc.)
  • ADR cross-reference linking (📝 ADR-0001 becomes a clickable link)
  • SPEC cross-reference linking (PREFIX-NNN links to spec requirement anchors)
  • Status/Date/Domain badge components
  • Requirement box components for spec tables
  • Consequence keyword highlighting (Good/Bad/Neutral) in ADRs
  • Dark mode support
  • Auto-generated sidebars

Supports two modes:

  • Scaffold mode: Creates a standalone docs-site/ with its own Docusaurus installation
  • Integration mode: Generates a build-time plugin into an existing Docusaurus site

Process​

Step 0: Resolve Artifact Paths​

<!-- Governing: ADR-0016 (Workspace Mode), SPEC-0014 REQ "Artifact Path Resolution" -->

Follow the Artifact Path Resolution pattern from $\{CLAUDE_PLUGIN_ROOT\}/references/shared-patterns.md § "Artifact Path Resolution" to determine the ADR, spec, and PRD directories. If $ARGUMENTS contains --module &lt;name>, resolve paths relative to that module; otherwise, in a workspace, aggregate across all modules. The resolved ADR directory is \{adr-dir\}, spec directory is \{spec-dir\}, and PRD directory is \{prd-dir\} (default docs/prds/, per 📝 ADR-0036).

<!-- Governing: ADR-0016 (Workspace Mode), SPEC-0014 REQ "Cross-Module Aggregation" -->

Cross-module aggregation: When in aggregate mode (no --module, workspace detected), include all modules' artifacts in the docs site. Organize the sidebar navigation by module:

Architecture/
├── api/
│ ├── ADRs/
│ │ ├── ADR-0001: Choose REST over GraphQL
│ │ └── ADR-0002: Choose PostgreSQL
│ └── Specs/
│ └── SPEC-0001: Web Dashboard
├── worker/
│ ├── ADRs/
│ │ └── ADR-0001: Choose Redis for queues
│ └── Specs/
│ └── SPEC-0001: Job Processing
└── Overview (cross-module index page)

Each module's artifacts are transformed independently and placed under a module-named directory in the docs output. The index page lists all modules with artifact counts. When --module is provided, generate docs for that single module only (flat structure, no module subdirectory). When in single-module mode (no workspace), operate normally with the existing flat structure.

Step 1: Pre-flight Checks​

  • Check if Node.js is installed. If not, tell the user: "Node.js is required to run the docs site. Please install it from https://nodejs.org/ and re-run this command." and stop.
  • Check if \{adr-dir\} has any ADR .md files
  • Check if \{prd-dir\} has any PRD-*.md files. PRDs are optional (📝 ADR-0036): when the directory is absent or empty, generate no PRD section and no empty placeholder page. When PRDs exist, give them their own sidebar section ahead of ADRs, matching the PRD → ADR → spec lineage, and render each PRD's governs: edges as links to the ADR and spec pages it governs.
  • Check if \{spec-dir\} has any spec directories (containing spec.md). Validate spec pairing per $\{CLAUDE_PLUGIN_ROOT\}/references/shared-patterns.md § "Spec Pairing Validation".
  • If NEITHER has content, tell the user: "No ADRs or specs found. Create some first with /sdd:adr or /sdd:spec, then re-run /sdd:docs." and stop.
  • If only one has content, proceed but note which is empty (e.g., "No specs found yet -- the docs site will only include ADRs for now.")

Step 2: Detect Existing Docusaurus Site and Upgrade State​

2.1: Check for upgrade manifest​

Check if .sdd-docs.json exists at the project root.

If .sdd-docs.json exists:

  • Read and parse the manifest
  • Check if the siteDir referenced in the manifest still exists on disk
    • If siteDir exists → enter Upgrade Mode (Step 3C). Skip Steps 2.2 and 2.3.
    • If siteDir is missing → warn the user: "Found .sdd-docs.json but the site directory \{siteDir\} no longer exists." Use AskUserQuestion to offer:
      • "Re-scaffold a new docs site" → proceed with Scaffold Mode (Step 3A)
      • "Cancel" → stop

If .sdd-docs.json does NOT exist, continue to Step 2.2.

2.2: Scan for existing Docusaurus sites​

Scan the project root for directories containing docusaurus.config.ts or docusaurus.config.js:

find . -maxdepth 2 -name 'docusaurus.config.*' -not -path './docs-site/*' -not -path './node_modules/*' 2>/dev/null
2.3: Choose mode​

If an existing docs site directory is detected (docs-site/ exists or an integration site was found in 2.2) but no .sdd-docs.json:

  • Warn: "Upgrade tracking unavailable — .sdd-docs.json not found."
  • Use AskUserQuestion to offer:
    • "Create manifest from current state" → compute SHA-256 checksums of all managed files in the existing site, write .sdd-docs.json using the current state as baseline, then enter Upgrade Mode (Step 3C)
    • "Continue without upgrade tracking" → proceed to mode selection below
    • "Cancel" → stop

If an existing non-scaffold Docusaurus site is found (from Step 2.2), use AskUserQuestion to let the user choose:

  • Option A: "Integrate into {directory}" -- proceed with Integration Mode (Step 3B)
  • Option B: "Scaffold a new docs site" -- proceed with Scaffold Mode (Step 3A)

If no existing site is found, proceed directly with Scaffold Mode (Step 3A).


Step 3A: Scaffold Mode​

Read and follow the plugin's skills/docs/references/scaffold-mode.md for the full scaffold workflow. After completion, proceed to Step 4 below.


Step 3B: Integration Mode​

Read and follow the plugin's skills/docs/references/integration-mode.md for the full integration workflow. After completion, proceed to Step 4 below.


Step 3C: Upgrade Mode​

Read and follow the plugin's skills/docs/references/upgrade-mode.md for the full upgrade workflow. This handles manifest-based file management, conflict resolution, and new template detection.


Step 4: Create Manifest​

Runs after Step 3A or 3B to establish upgrade tracking.

Determine managed files based on mode:

  • Scaffold: files in docs-site/plugins/sdd-content/, docs-site/src/components/, docs-site/src/css/, docs-site/src/theme/
  • Integration: files in \{site\}/plugins/sync-spec-docs/, \{site\}/src/components/design-docs/, \{site\}/src/css/design-docs.css, \{site\}/src/theme/MDXComponents.tsx (if created/modified)

Compute SHA-256 checksum for each file (shasum -a 256 \{file-path\}), then write .sdd-docs.json:

{
"version": "<plugin version from .claude-plugin/plugin.json>",
"mode": "scaffold" | "integration",
"siteDir": "<relative path to site dir>",
"createdAt": "<ISO 8601>",
"updatedAt": "<ISO 8601>",
"files": {
"<relative-path>": { "checksum": "sha256:<hex-digest>", "managed": true }
}
}

Tell the user: "Created .sdd-docs.json with {N} tracked files. Future runs of /sdd:docs will detect changes and offer upgrades."


Rules​

  • Always read templates from the plugin directory, don't recreate from memory
  • Configure the Docusaurus site for the current project (title, URLs, etc.)
  • The transform scripts must work with the project's actual directory structure
  • Don't include OpenAPI plugin config unless the project has an OpenAPI spec
  • Keep spec-emojis.json and spec-mapping.json as generated files (populated by build-spec-mapping.js)
  • In integration mode, NEVER overwrite the existing site's docusaurus.config.ts wholesale -- only add the plugin entry and CSS import
  • In integration mode, ALWAYS namespace components under design-docs/ to avoid collisions with existing components
  • In integration mode, generated files go to \{site\}/docs/architecture/ -- this directory is gitignored and regenerated on every build
  • Always create .sdd-docs.json after a fresh scaffold or integration install (Step 4)
  • Never delete or skip manifest creation -- it is required for upgrade tracking
  • During upgrades (Step 3C), always ask before overwriting user-modified files
  • The manifest files object uses project-root-relative paths as keys
  • Checksum format is always sha256:&lt;hex-digest> (lowercase hex)
  • When creating a manifest from an existing site (Step 2.3 "Create manifest from current state"), set all files to managed: true and use their current checksums as the baseline
  • In workspace aggregate mode, MUST organize docs navigation by module with per-module subdirectories (Governing: 📝 ADR-0016, SPEC-0014 REQ "Cross-Module Aggregation")
  • In workspace aggregate mode, MUST generate a cross-module index page listing all modules with artifact counts
  • In workspace aggregate mode, transform scripts run per-module with output directed to module-named subdirectories
  • When --module is provided, generate docs for that single module only using flat structure

Key Template Files Reference​

Scaffold Mode Templates (templates/docusaurus/)​

The templates directory contains production-ready versions of all files. The cp -r approach copies everything; you only need to customize docusaurus.config.ts and package.json.

Docusaurus Plugin (plugins/sdd-content/)​
  • index.js -- Consolidated Docusaurus plugin that:
    • Uses lib-artifact-transforms for YAML frontmatter parsing (replaces ~120 lines of custom YAML)
    • Builds the artifact graph per SPEC-0018 edge schema with 5 ADR edge types + 4 spec edge types
    • Generates MDX files from ADRs and specs with badges, RFC 2119 keyword highlighting, cross-references (Governing: 📝 ADR-0006, SPEC-0004)
    • Generates index pages (landing page, ADR section, spec section) with sidebar hierarchy diagrams
    • Generates the artifact graph page with stats, full Mermaid flowchart, and orphan lists
    • Implements getPathsToWatch() for native Docusaurus hot reload (replaces chokidar-cli + concurrently)

Integration Mode Templates (templates/integration/sync-spec-docs/)​

A self-contained Docusaurus plugin with adapted transform scripts.

Plugin Entry​
  • index.js -- Docusaurus plugin that runs transforms during loadContent() and watches source files via getPathsToWatch()
Transform Scripts (lib/)​
  • transform-adrs.js -- ADR transforms with parameterized paths
  • transform-openspecs.js -- OpenSpec transforms with parameterized paths
  • transform-utils.js -- Shared utilities (RFC 2119 keywords, cross-references, link fixing)
  • mdx-escape.js -- MDX v3 safety escaping
  • build-spec-mapping.js -- Spec ID mapping (returns data instead of writing files)
  • generate-index.js -- Index page generation with parameterized paths

Shared: React Components (templates/docusaurus/src/components/)​

Used by both modes. In scaffold mode, they live at docs-site/src/components/. In integration mode, they're copied to \{site\}/src/components/design-docs/.

  • StatusBadge.tsx -- Status with emoji (accepted, proposed, draft, etc.)
  • DateBadge.tsx -- Date display with calendar emoji
  • DomainBadge.tsx -- Domain/category badge
  • PriorityBadge.tsx -- P0-P4 priority levels
  • SeverityBadge.tsx -- Critical/High/Medium/Low/Info
  • RFCLevelBadge.tsx -- Maps RFC 2119 keywords to severity colors
  • RequirementBox.tsx -- Bordered container for spec requirements with ID anchors
  • Field.tsx / FieldGroup.tsx -- Metadata label-value pairs

Shared: Theme and CSS (templates/docusaurus/src/)​

  • src/theme/MDXComponents.tsx -- Registers all custom components for use in MDX
  • src/css/custom.css -- All badge, keyword, component, and dark mode styles

Reference​

integration-mode.md​

Generates a build-time Docusaurus plugin into an existing site. The plugin runs the same transforms as scaffold mode but writes output into the existing site's docs tree.

Let \{site\} be the path to the existing Docusaurus site directory (e.g., website/).

3B.1: Install dependencies and copy the plugin​

First, install lib-artifact-transforms in the site's package.json:

cd {site} && npm install lib-artifact-transforms@github:joestump/lib-artifact-transforms#main

Then copy the integration plugin template from the plugin's templates/integration/sync-spec-docs/ directory to \{site\}/plugins/sync-spec-docs/:

cp -r {plugin-path}/templates/integration/sync-spec-docs {site}/plugins/sync-spec-docs

If \{site\}/plugins/sync-spec-docs/ already exists, ask the user before overwriting.

3B.2: Copy React components​

Copy all component files from \{plugin-path\}/templates/docusaurus/src/components/ to \{site\}/src/components/design-docs/:

mkdir -p {site}/src/components/design-docs
cp {plugin-path}/templates/docusaurus/src/components/*.tsx {site}/src/components/design-docs/

3B.3: Add CSS styles​

Read \{plugin-path\}/templates/docusaurus/src/css/custom.css and create \{site\}/src/css/design-docs.css containing ONLY the design-specific styles. Exclude the :root \{ ... \} and [data-theme='dark'] \{ ... \} CSS variable blocks at the top of the file (the ones that set --ifm-color-primary-* and --docusaurus-highlighted-code-line-bg). These are Docusaurus theme colors that would override the existing site's color scheme.

Include everything from the /* Badge Components */ comment onwards.

Then add the CSS import. Check how the site loads custom CSS:

  • If the site's docusaurus.config.ts has a customCss option, add './src/css/design-docs.css' as an additional entry (it can be an array)
  • Otherwise, add @import './design-docs.css'; at the top of the site's existing custom CSS file

3B.4: Register MDX components​

Check if \{site\}/src/theme/MDXComponents.tsx exists:

If it does NOT exist, create it:

import React from 'react';
import MDXComponents from '@theme-original/MDXComponents';
import DateBadge from '@site/src/components/design-docs/DateBadge';
import DomainBadge from '@site/src/components/design-docs/DomainBadge';
import PriorityBadge from '@site/src/components/design-docs/PriorityBadge';
import SeverityBadge from '@site/src/components/design-docs/SeverityBadge';
import StatusBadge from '@site/src/components/design-docs/StatusBadge';
import RFCLevelBadge from '@site/src/components/design-docs/RFCLevelBadge';
import RequirementBox from '@site/src/components/design-docs/RequirementBox';
import Field from '@site/src/components/design-docs/Field';
import FieldGroup from '@site/src/components/design-docs/FieldGroup';

export default {
...MDXComponents,
DateBadge,
DomainBadge,
PriorityBadge,
SeverityBadge,
StatusBadge,
RFCLevelBadge,
RequirementBox,
Field,
FieldGroup,
};

If it DOES exist, read the existing file and merge the design-docs imports: add import lines for each component from @site/src/components/design-docs/, add component names to the default export, and preserve all existing imports and registrations.

3B.5: Register the plugin in docusaurus.config​

Read \{site\}/docusaurus.config.ts (or .js) and add the sync plugin to the plugins array. Determine the correct projectRoot by computing the relative path from \{site\} to the project root.

Example -- if the site is at website/ and the project root is ..:

plugins: [
['./plugins/sync-spec-docs', {
projectRoot: '..',
docsPath: 'docs', // adjust to match the site's existing docs path
}],
],

To find the existing docs path, look for the path option in the classic preset's docs config. If not specified, Docusaurus defaults to 'docs'.

If the config already has a plugins array, append to it. If not, add a new plugins property.

3B.6: Add .gitignore entries​

Check for .gitignore at the project root. Add entries for the generated output directory:

# Design docs (generated by sync-spec-docs plugin)
{site}/docs/architecture/

3B.7: Run initial build and verify​

cd {site} && npx docusaurus build 2>&1 | tail -20

If the build fails, diagnose and fix. Common problems:

  • Missing dependencies: run npm install in the site directory
  • MDXComponents merge conflict: check the merge was done correctly
  • Plugin path error: verify the relative projectRoot is correct

3B.8: Update .claudeignore​

Add entries to ignore the site's build artifacts:

{site}/node_modules/
{site}/build/
{site}/.docusaurus/

3B.9: Report results​

Tell the user what was created:

  • Plugin installed at \{site\}/plugins/sync-spec-docs/
  • Components installed at \{site\}/src/components/design-docs/
  • CSS added at \{site\}/src/css/design-docs.css
  • Generated docs will appear at \{site\}/docs/architecture/
  • The plugin auto-syncs when ADRs or specs change during npm run start

Then ask: "Integration complete! Want me to start the dev server? (cd \{site\} && npm run start)"

After completion, proceed to Step 4: Create Manifest (back in SKILL.md).

scaffold-mode.md​

Creates a standalone Docusaurus site at docs-site/.

  1. Check for existing docs-site: Look for docs-site/ in the project root. If it exists, ask the user before overwriting.

  2. Copy the plugin's Docusaurus templates using cp -r from the plugin's templates/docusaurus/ directory to docs-site/ in the project root.

  3. Customize for the project by reading and modifying only these files:

    • docs-site/package.json -- update the project name from $ARGUMENTS or inferred from the repo
    • docs-site/docusaurus.config.ts -- update title, baseUrl, and GitHub URL for this project
    • Optionally customize the sdd-content plugin options if your ADRs/specs are in non-standard locations:
      • adrsDir (default: ../docs/adrs)
      • specsDir (default: ../docs/openspec/specs)
      • outputDir (default: ../docs-generated)
  4. Run npm install in the docs-site directory.

  5. Update .claudeignore: Check if .claudeignore exists at the project root. If not, create it. Add entries to ignore:

    docs-site/node_modules/
    docs-site/build/
    docs-site/.docusaurus/

    If .claudeignore already exists, append any missing entries.

  6. Report and offer to start: Tell the user what was created, then ask: "Docs site created! Want me to start the dev server? (cd docs-site && npm run start)"

After completion, proceed to Step 4: Create Manifest (back in SKILL.md).

upgrade-mode.md​

Entered when .sdd-docs.json exists and the referenced siteDir is present on disk. Updates an existing docs installation to the latest plugin templates while preserving user customizations.

Read the manifest from .sdd-docs.json. Let \{mode\} be the manifest's mode field ("scaffold" or "integration"), and \{site\} be the resolved siteDir.

3C.1: Determine template source paths​

Based on the manifest's mode:

  • Scaffold: template root is \{plugin-path\}/templates/docusaurus/
  • Integration: template root is \{plugin-path\}/templates/integration/sync-spec-docs/ for plugin files, and \{plugin-path\}/templates/docusaurus/src/components/ for shared components

3C.2: Process each managed file​

For each entry in the manifest's files object where managed is true:

  1. Compute the current SHA-256 of the file on disk
  2. Compare against the manifest's stored checksum:
    • Checksums match (file unmodified by user) → replace silently with the new template version
    • Checksums differ (user has modified the file) → use AskUserQuestion:
      • "Accept new version" → overwrite with the template version
      • "Keep current" → leave as-is, update manifest checksum to current hash
      • "Opt out of management" → set managed: false in manifest (skip in future upgrades)
    • File missing from disk → re-create from the template

For entries where managed is false, skip entirely.

3C.2b: Pre-plugin migration detection (Scaffold mode only)​

If scaffold mode AND \{site\}/scripts/ exists BUT \{site\}/plugins/ does NOT exist:

This is a pre-plugin installation (using the old 8-script approach). Offer the user:

  • "Migrate to new plugin" → delete \{site\}/scripts/, \{site\}/src/data/spec-mapping.json, \{site\}/src/data/spec-emojis.json (if present); install the new plugins/sdd-content/index.js; update package.json (remove chokidar-cli, concurrently, build-content/watch-content scripts); update docusaurus.config.ts to register the plugin
  • "Keep current setup" → do not migrate; set all managed files to managed: false

3C.3: Detect new template files​

Check for files in the current plugin templates that are NOT listed in the manifest:

  • For scaffold: scan templates/docusaurus/plugins/sdd-content/, templates/docusaurus/src/components/, templates/docusaurus/src/css/, templates/docusaurus/src/theme/
  • For integration: scan templates/integration/sync-spec-docs/, templates/docusaurus/src/components/

For each new file: install it to the appropriate location and add to the manifest with managed: true and its SHA-256 checksum.

3C.4: Update the manifest​

Write the updated .sdd-docs.json:

  • Set version to the current plugin version from .claude-plugin/plugin.json
  • Set updatedAt to the current ISO timestamp
  • Update all checksum values to reflect the current on-disk state
  • Preserve createdAt and mode from the original manifest

3C.5: Ensure .claudeignore exists​

Check if .claudeignore includes ignore entries for \{site\}/node_modules/, \{site\}/build/, and \{site\}/.docusaurus/. If any are missing, append them.

3C.6: Run build and verify​

  • For scaffold: run npm install in \{site\} if package.json changed, then offer to start the dev server
  • For integration: run a Docusaurus build to verify the plugin still works

3C.7: Report results​

Tell the user:

  • Files updated silently (checksum matched)
  • Files with conflicts and what the user chose for each
  • New files added
  • Files skipped (managed: false)
  • New plugin version recorded in the manifest

Example Invocations​

generate the docs site from our ADRs and specs
/sdd:docs
scaffold a Docusaurus site that mirrors our design artifacts
rebuild the documentation site with the latest ADRs
set up a docs site so we can publish our architecture decisions