CrewRig

Documentation publication contract

CrewRig's technical documentation is a structured body of reference material that ships inside the framework. This page is the normative contract for how each documentation page declares its place in that structure, how a machine-readable index of the public subset is derived, and how a separate website repository consumes that index without coupling to CrewRig's internal directory layout. It realizes spec 0027.

Top-level sections

Every page that belongs to a top-level documentation section belongs to exactly one of the following eight sections, in this fixed order:

# section value Title
1 introduction Introduction
2 concepts Concepts
3 adoption Adoption
4 authoring Authoring
5 lifecycle Lifecycle
6 harness-engineering Harness engineering
7 reference Reference
8 architecture-adr Architecture & ADRs

This enumeration is the closed set of permitted section values. Adding, removing, or reclassifying a section requires a delta-spec amendment to spec 0027 (spec 0027 R10); it is not a routine documentation edit.

Per-page metadata block

Each documentation page carries its metadata in a single HTML comment — the metadata block. The block is invisible when the page is rendered on github.com or by any standard Markdown renderer, yet it is trivially machine-parseable. YAML frontmatter is deliberately not used: github.com renders frontmatter as a visible table, which would regress the in-repo reading experience for every page.

Placement

The metadata block appears on its own line, immediately after the page H1. Some pages open with an extraction banner comment on line 1 (for example <!-- Extracted from AGENTS.md. -->) followed by the H1; the metadata block still goes after the H1, regardless of any preceding banner. There is at most one metadata block per page.

Grammar

The block is exactly one HTML comment of this form:


  • The literal sentinel is crewrig-doc:. The parser keys on this sentinel; a comment that does not begin with it is ignored.
  • Each entry is a key=value pair. Pairs are separated by one or more spaces. Key order is not significant — the parser sorts keys into a canonical order before emitting the index.
  • A value is either a bare token or a double-quoted string:
    • A bare token contains no spaces and no double-quote characters (for example section=lifecycle, nav_order=20, published=true).
    • A double-quoted string is wrapped in " and may contain spaces (for example title="Plan format and review"). A value that contains a space MUST be double-quoted; an unquoted value that contains a space is a malformed block.
  • The characters " and > are FORBIDDEN inside any value, quoted or not. A > would prematurely close the surrounding HTML comment and break every renderer; a " would break quoting. The generator rejects a block whose values contain either character.
  • A published=true page whose block is missing any required field, or carries an unknown section value, is a hard error: the generator fails rather than silently dropping the page (spec 0027 Scenario 4).

Fields

Field Required Permitted values Meaning
title yes quoted string or bare token Human-readable navigation title. A title containing spaces MUST be double-quoted.
section yes one of the eight section values above The top-level section the page belongs to.
nav_order yes non-negative integer Position within the section's reading order (ascending).
published yes true or false Whether the page is part of the public documentation set.

A page with published=false still declares the block, but only published is required for it; section, nav_order, and title may be omitted. An unpublished page never appears in the generated index (spec 0027 R4) yet remains in the repository for contributors (spec 0027 R12 — unassigned files default to unpublished).

Example

# Plan format and review


The generated index — docs/index.json

docs/index.json is the single machine-readable manifest of the public documentation set. It is generated by scripts/build-docs-index.sh from the per-page metadata blocks and committed to the repository, so a separate site repository can fetch it by URL alone — without cloning CrewRig or running any CrewRig tooling (spec 0027 R5, R9).

Schema

{
  "version": 1,
  "sections": [
    {
      "section": "reference",
      "title": "Reference",
      "pages": [
        {
          "title": "CLI support matrix",
          "path": "docs/cli-matrix.md",
          "nav_order": 10
        }
      ]
    }
  ]
}
  • version — manifest schema version. Currently 1.
  • sections — array of sections that contain at least one published page, emitted in the fixed eight-section order above. Empty sections are omitted.
  • For each section: section (the enum value), title (the human-readable title from the table above), and pages.
  • pages — published pages in that section, sorted by nav_order ascending, then by path lexicographically as a deterministic tie-breaker. Each page carries title, path (repository-root-relative POSIX path), and nav_order.

The emitter is deterministic: stable key order, fixed section order, stable page sort, and a trailing newline. Re-running the generator on an unchanged tree produces a byte-identical file, which is what makes the --check drift guard reliable.

Consuming the manifest from a site repository

A separate site repository (for example crewrig-website) renders crewrig.org/docs from docs/index.json alone:

  1. Fetch docs/index.json by raw URL from the CrewRig repository at the pinned ref.
  2. Walk sections in array order to build the navigation tree; within each section, walk pages in array order.
  3. For each page, fetch the Markdown body at path (also by raw URL), strip the metadata block (the HTML comment is inert to renderers anyway), and render the body.

The site repository never needs to know CrewRig's internal directory layout: the manifest is the contract. The metadata-block grammar above is the only CrewRig-internal detail a site build must understand if it chooses to read page blocks directly rather than relying on the manifest.

The generator — scripts/build-docs-index.sh

scripts/build-docs-index.sh scans docs/**/*.md, parses each page's metadata block, and emits docs/index.json.

Invocation Behavior
bash scripts/build-docs-index.sh Regenerate docs/index.json in place.
bash scripts/build-docs-index.sh --check Regenerate to a temp file, diff against the committed docs/index.json, exit non-zero on drift. Also runs the lint pass.

The lint pass (run under --check, and on every default run before writing) fails on any of:

  1. A published=true page missing a required field (title, section, nav_order, or published).
  2. A page declaring an unknown section (not one of the eight).
  3. A value containing a forbidden " or > character.
  4. An orphan in either direction: a docs/index.json entry whose path does not resolve to a file, or a published page absent from the committed manifest (drift).

CI runs bash scripts/build-docs-index.sh --check in the check-components job of .github/workflows/build.yml, mirroring the component-drift guard.

Organization overlay

An adopting organization adds its own documentation pages under docs/org/ using the identical metadata block. Those pages are excluded from upstream sync (.crewrig/core-paths.txt), so they never flow back to CrewRig (spec 0027 R7). The organization's own site build unions the core manifest (docs/index.json) with an overlay manifest it generates over docs/org/**, rendering core and overlay pages under one navigation tree against the same contract (spec 0027 R8). See docs/org/README.md.