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โ€‹

Transform ADRs and OpenSpec specs (located via the Artifact Path Resolution pattern from references/shared-patterns.md) 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 references/shared-patterns.md to determine the ADR and spec 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\} and spec directory is \{spec-dir\}.

<!-- 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 \{spec-dir\} has any spec directories (containing spec.md). Validate spec pairing per 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