Docs Index Contract
OAT docs navigation starts from authored docs/**/index.md files. Each ## Contents section is the local source of truth for sibling pages and child directories. Generated artifacts are derived from docs source and should not be edited directly. The framework determines which generated artifact is produced, but the authored ## Contents contract is the same for humans and agents.
Rules
- Every non-excluded Markdown-bearing content directory must contain an authored
index.md; asset-only directories are exempt. - Preserve useful audience/scope context, ownership guidance, and existing local instructions. Authored pages need nonempty title/description metadata.
- Every
index.mdmust include a## Contentssection. - The
## Contentssection is the machine-readable local map for sibling pages and child directories. - Every
## Contentslink should use a.md-suffixed relative target, including child directory links such assubdir/index.md. - Do not hand-edit generated navigation or generated root-index artifacts.
- For Fumadocs, refresh or freshness-check the generated app-root manifest after adding, removing, or renaming Markdown files. Compare that manifest against authored
## Contentsmaps for drift; reordering## Contentsdoes not reorder the generated manifest's file-tree sort. - Run
oat docs nav syncafter adding, removing, renaming, or reordering pages. It regenerates the framework's navigation from authored## Contentsmaps and preserves the order declared in each local map: thenav:block inmkdocs.ymlfor MkDocs, and onemeta.jsonper docs directory for Fumadocs.
## Contents format
Use Markdown bullet links for sibling pages and child directories:
## Contents
- [Getting Started](getting-started.md) - Setup and local workflow.
- [Reference](reference/index.md) - Reference pages for the subsystem.Notes:
- Links after
## Contentscan include short human-readable descriptions. - Child directories should link to their
index.md. - Leaf pages should link to their
.mdfilename. - Prose outside
## Contentsis ignored by nav generation and remains freeform; it can explain scope, reader paths, or migration status.
Plain Markdown Ownership
Configured Markdown uses documentation.root literally, even with a child named
docs. The configured <root>/index.md is authored context plus a Contents map;
edit it directly. Bootstrap/adoption creates missing baseline files and root
guidance, but content gaps remain analyze/apply work. No app package, site build,
nav sync, default manifest, or docs-root AGENTS creation is required.
Optional inventories need explicit output outside the full configured content
tree, for example oat docs generate-index --docs-dir docs --output .oat/docs-manifest.md.
Default generation is refused, as is output to the authored index or any part of
the full root, even with narrowed source flags or symlink aliases. Generation
never repoints the configured authored index.
Fumadocs Generation
For this Fumadocs app, rendered page routing comes from the Fumadocs file/source pipeline over apps/oat-docs/docs, and the sidebar order comes from the committed meta.json files that oat docs nav sync writes (see Fumadocs Nav Sync). The generated root manifest, apps/oat-docs/index.md, is an inventory for agents and tooling; it is not the rendered sidebar/page-tree source.
oat docs generate-index walks the Markdown file tree under docs/ and writes the app-root generated manifest. The app scripts run:
fumadocs-mdx
pnpm -w run cli:source -- docs generate-index --docs-dir apps/oat-docs/docs --output apps/oat-docs/index.mdoat docs generate-index rewrites the generated root manifest from the docs source tree. Run it after adding, removing, or retiring pages in this Fumadocs app, and run oat docs nav sync as well so the sidebar's meta.json files follow the same change. The two commands produce different artifacts: generate-index writes the agent-facing inventory and nav sync writes the sidebar navigation.
Fumadocs generated behavior:
- Generated entries are ordered by the file-tree generator:
index.mdfirst, directories before files, then lexical order. - Reordering a
## Contentsblock does not reorder the generated manifest's file-tree sort. - Generated manifests should carry an autogen warning and are rewritten by
predev/prebuild.
Fumadocs Nav Sync
In a Fumadocs app (detected by its source.config.ts), oat docs nav sync --target-dir <docs-app-dir> writes one meta.json beside every docs directory index.md. The files are generated and committed; edit the ## Contents map, not the meta.json.
Fumadocs generated behavior:
pagesfollows the order of the directory's## Contentslinks. The root list starts withindex; a child directory appears by its folder name, and its ownindex.mdbecomes that folder's landing page. A folder whosemeta.jsonkeepsroot: truealso listsindexfirst, because Fumadocs gives a root folder no implicit landing page.- Navigation is strict: there is no
"..."rest entry. A page or folder that no## Contentsmap lists stays out of the sidebar, and the command reports it by path in its human output and in--json(unlisted). Add the page to its directory's## Contentsmap to show it. - A
## Contentslink to a page in another directory is written as a Fumadocs link entry such as[Writing Skills](/contributing/skills), so each page belongs to exactly one folder. - A page or folder whose name Fumadocs would read as a
pagesdirective, such as!hidden,z...a,...name, or---, is written in the local-path form./!hiddenso it stays a page entry. - The folder
titlecomes from theindex.mdfrontmattertitle, falling back to its first#heading. - Keys nav sync does not own, such as
iconordefaultOpen, are kept. - Existing files are compared by meaning, not bytes, so a second run with no docs changes writes nothing, even after a formatter rewrites the files.
.mdand.mdxpages can both be listed; each appears inpagesby its file name without the extension.
oat docs nav sync --check computes the same result and writes nothing. It exits 1 when a meta.json file would change or a page or folder is unlisted, and names each one. In this app, prebuild runs it, so pnpm build:docs fails until the ## Contents maps and the committed meta.json files agree.
MkDocs Nav Sync
MkDocs apps use oat docs nav sync --target-dir <docs-app-dir> to walk the docs tree from docs/index.md downward and regenerate the nav: block in mkdocs.yml from discovered directory index.md files.
MkDocs generated behavior:
- Root
docs/index.mdbecomesHome. - Child directory
index.mdfiles become section landing pages. - Nested entries are emitted in the order they appear under each local
## Contentsblock. mkdocs.ymlmay contain other configuration, but itsnav:block is derived from authored## Contents.
Generated-file boundaries
- Edit authored files under the resolved content root (
docs/inside framework apps, or the literal configured Markdown root), especially the nearestindex.mdand## Contents. - Do not hand-edit a Fumadocs app-root generated
index.md; regenerate it from the docs source tree. - Do not hand-maintain MkDocs
nav:entries or Fumadocsmeta.jsonpageslists when the local workflow usesoat docs nav sync. - If a Fumadocs generated manifest lists pages that are missing from authored
## Contents, treat that as authored-source drift or intentional generator-inventory behavior to verify before relying on the generated file as navigation evidence.
Authoring guidance
- Use
index.mdas the local discovery surface for humans and agents. - Add a short topic description next to each link so agents can choose the right file without opening every page.
- Update
## Contentswhenever you add, remove, rename, or reorder docs files in a directory. - Markdown checks authored files/links, regenerating optional external manifests only when declared. Frameworks regenerate their artifacts after structural changes:
nav syncfor MkDocsmkdocs.ymland Fumadocsmeta.jsonnavigation, plusgenerate-indexfor Fumadocs root manifests. - Refresh or freshness-check the generated artifact before committing structural docs changes.
If You Are Trying To...
- learn the docs workflow or docs commands as a user, start with Docs Tooling
- contribute or restructure docs in this repo, pair this contract with Contributing to OAT Docs