Skip to main content
This page is the authoritative reference for anyone setting up docs in a new exegia repo.
This supersedes the git-submodule approach from issue #3 / PR #5, which does not work — see Why not submodules. Direction history is recorded in issue #9.

Chosen approach

One Mintlify project. A CI job mirrors each source repo’s docs/ into this repository and merges its navigation. Each exegia repository that wants a section on the org docs site:
  1. Maintains its own docs/ directory with .mdx files and a docs.json containing a navigation block. This doubles as its standalone preview config.
  2. Files a section request by opening a PR that adds sections/<slug>.yml here (see Filing a section request).
  3. Adds a small workflow that pings this repo when its docs change (see Wiring up the source repo).
From then on it is automatic. The Mirror sections workflow clones each active source, copies its docs into content/<slug>/, regenerates that section’s navigation in docs.json, and commits. Mintlify’s GitHub App sees the commit and rebuilds.

Why this approach

Why not submodules

The original strategy added each source repo as a git submodule at content/<slug>/. Mintlify’s builder clones this repository without --recurse-submodules, so those directories are empty at build time. The failure is silent: docs.json is processed normally, so the navigation entries render and appear in the sidebar — every one of them leading to a 404. No build error, no dashboard warning. Confirmed empirically in PR #12 against a real preview deployment. Mirroring exists because Mintlify only ever sees one repository. It is also what Mintlify’s own documentation recommends for content that lives in another repo.

Repository layout

Everything under content/ is generated. Edits there are reverted on the next mirror run, and CI fails the PR that made them. Fix the source repo instead.

Filing a section request

Open a PR against this repository adding sections/<slug>.yml:

Acceptance gate

A request is accepted once the source repo has, at docs_path:
  • a valid docs.json with a navigation block (either tabs or groups), and
  • at least one .mdx page.
There is no navigation review step — the source repo owns its own structure.

Activating a section

1

Set status to active

Change status: pending to status: active in sections/<slug>.yml and merge.
2

Let the mirror run

Merging to main triggers Mirror sections. It clones the source, populates content/<slug>/, regenerates the navigation, and commits. Run it manually from the Actions tab if you don’t want to wait.
3

Wire up the source repo

Add the dispatch workflow below so future changes propagate on their own.
No dashboard step, and nothing to grant Mintlify access to — it only ever reads this repository.

Wiring up the source repo

Without this, a source repo’s changes only reach the site on the nightly run.
CORPORA_DOCS_DISPATCH_TOKEN needs contents: write on exegia/corpora-docs. Set it as an org-level secret so each new source repo doesn’t need its own.
The token check is not optional boilerplate. Without it, a repo that adds this workflow before the secret exists gets a red X on every docs push. Skipping with a warning means the workflow can be merged ahead of the secret and starts working the moment it appears — and the nightly mirror covers the gap.
Live reference implementation: corpora-auth/.github/workflows/notify-docs.yml. The mirror rewrites root-relative links that point at pages within the same section. A source page linking to /quickstart means its quickstart; left alone it would land on this site’s /quickstart. The mirror rewrites it to /content/<slug>/quickstart. Links to anything else — external URLs, or hub pages — are left untouched. To link into a section from elsewhere, use the full mirrored path:

Sections registry

What CI checks

Reconcile sections runs on any PR touching sections/, content/, docs.json, or the mirror script, and fails if:
  • an active section has no content/<slug>/ directory,
  • a content/<slug>/ directory has no matching sections/<slug>.yml,
  • re-running the mirror produces anything different from what is committed — which covers hand-edited content/, a hand-edited docs.json navigation, and a source repo whose docs have moved on.
The mirror also emits a warning for any mirrored page the source’s own navigation never references. Those pages deploy and are reachable by URL but appear in no sidebar, which is nearly always an oversight in the source repo.

Known limits

  • Staleness window. A source repo without the dispatch workflow is up to 24 hours stale. With it, propagation takes about a minute.
  • label must be unique across sections — it is the top-level sidebar group name, and the mirror matches on it when regenerating.
  • Mirrored pages live under /content/<slug>/. Prettier URLs would need Mintlify’s native multi-repo feature (Enterprise) or a redirect layer.
  • Private source repos need DOCS_SOURCES_TOKEN set on this repo with read access to them. Public sources need no token.
  • Only pages the source navigation references are mirrored. A docs/ directory frequently holds Markdown that isn’t documentation — agent SKILL.md files, notes, templates — and that content routinely breaks MDX parsing. If a page is missing from the site, check that the source’s docs.json lists it.
  • The drift check clones sources live, so a PR touching only docs.json can fail because an unrelated source repo moved on since the last mirror run. Re-run the Mirror sections workflow and rebase.