How to Add a New Docs Page
How to Add a New Docs Page
Section titled “How to Add a New Docs Page”This guide covers everything you need to add a new .mdx page to xrmghost-docs and have it appear on the published documentation site.
1. Find the Right Product Owner
Section titled “1. Find the Right Product Owner”Before writing anything, confirm your change falls within your team’s ownership area:
- Open the relevant architecture and section landing pages, starting with Source of Truth.
- Locate the section that matches the content you want to add (e.g.
src/content/docs/cli/,src/content/docs/attributes/). - Check the existing section docs, reviewers, and repo conventions to confirm who owns that slice.
- If the section does not exist yet or the owner is unclear, contact the Documentation team as the interim owner.
If you are adding a net-new section (a new product area), align with the Documentation team first so ownership and navigation are agreed before the page lands.
2. Choose the Right Folder
Section titled “2. Choose the Right Folder”The src/content/docs/ folder hierarchy mirrors the site navigation. Follow these naming rules:
| Rule | Example |
|---|---|
| Use lowercase, hyphen-separated folder names | src/content/docs/my-product/ |
Each section must have an index.mdx as its landing page | src/content/docs/my-product/index.mdx |
| Sub-sections live in nested folders | src/content/docs/my-product/advanced/index.mdx |
| Do not invent deeply nested hierarchies speculatively — start flat | src/content/docs/my-product/getting-started.mdx |
If a folder already exists for your product area, add your page there. Do not create a parallel folder.
3. Create the File
Section titled “3. Create the File”Create a new .mdx file in the appropriate folder. The file name should be lowercase and hyphen-separated.
src/content/docs/my-product/my-new-page.mdx4. Write the Frontmatter
Section titled “4. Write the Frontmatter”Every .mdx file must begin with a YAML frontmatter block. Two fields are required:
---title: My New Pagedescription: A one-sentence summary of what this page covers.---Frontmatter Rules
Section titled “Frontmatter Rules”| Field | Required | Notes |
|---|---|---|
title | Yes | Shown in navigation and browser tab. Keep it short (≤ 60 chars). |
description | Yes | One sentence. Used in SEO meta tags and link previews. |
| Additional fields | No | Only add fields that Starlight’s content schema explicitly supports. Do not invent fields. |
The build will reject any .mdx file that is missing title or description.
5. Write Honest Content
Section titled “5. Write Honest Content”-
If the content is not ready, use an explicit TODO marker rather than inventing placeholder content:
> **TODO:** This section will be expanded in [story/ticket reference]. -
Fake or hallucinated content is harder to fix than an honest placeholder and misleads readers.
-
Cite the ADO story ID when the TODO has a known follow-up owner.
5.1 Template Learnings from the First Real Docs Slice
Section titled “5.1 Template Learnings from the First Real Docs Slice”The first repo-level public docs slice for src/content/docs/attributes/ exposed a few reusable lessons for future work:
- Start from a real package surface, not the template headings. Pull examples and terminology from the source package README or code so the first draft is anchored in what actually exists.
- Separate narrative guidance from generated reference early. If exhaustive schema pages are not available yet, document the package purpose and usage shape now, and reserve a future location such as
src/content/docs/<area>/schema/for generated content later. - Use bounded TODOs only for missing reference material. Narrative basics such as purpose, audience, and a starter example should be written as soon as they are known; TODO markers should remain limited to honestly missing generated or machine-derived content.
- Record template gaps when they appear. If a placeholder page required extra explanation about source-of-truth boundaries or future generated content, add that guidance here so the next team does not rediscover it from scratch.
5.2 CLI Docs Contributor Decision Path
Section titled “5.2 CLI Docs Contributor Decision Path”When making CLI-related documentation changes, choose your path based on what you are changing:
Path A — Narrative-only change (stays in xrmghost-docs)
Section titled “Path A — Narrative-only change (stays in xrmghost-docs)”You are editing the conceptual overview, getting-started guide, or any human-written explanation of the CLI.
- Files:
src/content/docs/cli/index.mdx,src/content/docs/cli/getting-started.mdx(or other narrative files outsidesrc/content/docs/cli/reference/). - Where to work: This repository (
xrmghost-docs). - PR target:
xrmghost-docsdev. - Reviewer: Documentation team or CLI team.
- Do not touch
src/content/docs/cli/reference/files in this PR.
Path B — Generator or source-driven change (starts in xrmghost-cli)
Section titled “Path B — Generator or source-driven change (starts in xrmghost-cli)”You are changing a CLI command, its --help text, its flags, or the command manifest that feeds the reference generator.
- Where to work:
xrmghost-clirepository. - PR target:
xrmghost-cli(its own review and merge process). - Effect on
xrmghost-docs: After thexrmghost-clichange merges and the generator runs, updated files land undersrc/content/docs/cli/reference/automatically. Do not manually replicate those changes inxrmghost-docs. - Reviewer: CLI team in
xrmghost-cli. Approval inxrmghost-docsdoes not substitute for approval inxrmghost-cli.
Path C — Coordinated docs-plus-generator change (linked workstream or single shared PR)
Section titled “Path C — Coordinated docs-plus-generator change (linked workstream or single shared PR)”You need to update both the CLI source/generator in xrmghost-cli and narrative or contract documentation in xrmghost-docs as part of the same logical change (for example, a new command that also needs a narrative walkthrough, or a generator contract change that also updates architecture docs).
- Acceptable approach: A single shared PR or coordinated workstream that touches both repositories is acceptable when both sides must move together.
- Required: The PR or workstream description must clearly identify which changes are narrative (owned by
xrmghost-docs) and which are source/generator changes (owned byxrmghost-cli), with appropriate reviewers from each team. - Not acceptable: Using a shared PR as a bypass to skip
xrmghost-clireview for generator or source changes, or to manually edit generated files insrc/content/docs/cli/reference/without running the generator. - Do not let the shared PR scope drift into editing generated reference files directly. Generated content under
src/content/docs/cli/reference/must always originate from the generator run, not from hand edits.
For the current public rules, use this guide together with Source of Truth. If the CLI ownership split or generation contract is unclear, stop and confirm it with the Documentation and CLI teams instead of guessing.
5.3 QueryEngine Operator Reference Maintenance
Section titled “5.3 QueryEngine Operator Reference Maintenance”The QueryEngine operator-support reference (src/content/docs/query-engine/operator-support.mdx) is
transcribed by hand from frozen snapshots of xrmghost-framework-host. It is the one content
path in this repository with no generator behind it. This section is the authoritative contributor
procedure for that rule; docs/query-engine/sources/README.md documents the snapshots themselves and
their provenance. Keep the two in agreement instead of restating the procedure anywhere else.
What the snapshots are
Section titled “What the snapshots are”- The snapshots live under
docs/query-engine/— the generated matrixdocs/query-engine/operator-support-matrix.generated.mdand seven.cs.txtsource copies underdocs/query-engine/sources/. - They sit outside
src/content/, so they are never published. The.txtextension is there so nobody tries to compile them. - They are read-only copies. Never hand-edit a snapshot, not even to fix a typo or to make a line agree with the published page: an edit here would make the engine say something the engine does not say, and the whole point of keeping the copies next to the page is that the derivation can be checked by diffing two files that sit side by side.
- Current provenance:
xrmghost-framework-host@ff32df7(branchdev), taken on 18 September 2026. Coverage is closed at 88 of the SDK’s 89 condition operators —childofis the only deliberate refusal, andmasksselectis supported without having a FetchXML spelling — and continuous evolution is not expected, which is why a dated, signed copy was chosen over permanent cross-repo infrastructure.
Which snapshot answers which question
Section titled “Which snapshot answers which question”- FetchXML spellings and the SDK pin come from
OperatorContractTests.cs.txt(fieldFetchXmlSpellings), which carries 91 spellings covering 88 of the 89 SDK condition operators — more spellings than operators becauseEqualandNotEqualeach accept more than one FetchXML spelling, and one operator fewer than the inventory becauseMasksSelecthas no FetchXML spelling at all. It is the single entry ofOperatorsWithoutAFetchXmlSpellingin the same file. FetchXmlOperatorMap.cs.txtis not enough. It holds only the 24 spellings thatOperatorIdentity.Normalizecannot reach on its own; every spelling that differs from the SDK member name by separators alone is absent by design. Deriving the full list from it loses most of it.- Resolving a spelling is not supporting an operator. A spelling resolves to an operator identity;
whether the engine can evaluate it is
IConditionEvaluatorRegistry.IsSupported’s answer. Never use the presence of a spelling as evidence of support. - The SDK pin is
Microsoft.CrmSdk.CoreAssemblies9.0.2.45.AssemblyVersion 9.0.0.0is not the pin: that package ships an assembly whoseAssemblyVersionis9.0.0.0and whoseFileVersionis9.2.47.9489, and9.0.0.0stays9.0.0.0whichever package version delivered it. Citing it as the pin would make the public reference non-reproducible.
When the engine changes
Section titled “When the engine changes”Nothing notices automatically, and nothing should. For this flow only there is no CI comparison
between the two repositories, no generator, no verification tool and no automatic cross-repo link —
unlike the CLI reference in Path B
above, which is populated by a real cross-repo generator from xrmghost-cli. Pick a commit of
xrmghost-framework-host and replace things by hand, in this order:
docs/query-engine/operator-support-matrix.generated.md, regenerated from the newxrmghost-framework-hostcommit. It is the inventory the page transcribes dispositions, required context and refusal reasons from, so it comes first.- The seven
.cs.txtcopies underdocs/query-engine/sources/, replaced whole from the same commit. - The provenance line — commit and date — in
docs/query-engine/sources/README.md, in the header of the generated matrix, and in the provenance block of the published page. - Re-transcribe and re-review
src/content/docs/query-engine/operator-support.mdxagainst the matrix and the seven copies. That comparison against the sources is the review; no tool performs it, and it is a one-off per engine change, not a standing job.
Replacing only the .cs.txt copies while leaving the old matrix published is the failure to avoid:
dispositions and required context come from the matrix, not from the contract copies, so the page would
describe an engine that no longer exists while its provenance claims it is current. Nothing catches
that — for this flow the only automated gate is npm run build, which proves the site compiles,
not that it tells the truth.
Where the re-transcribed page goes live
Section titled “Where the re-transcribed page goes live”xrmghost-docs is a standalone site: there is no portal submodule to advance and no sync step to
run. Once the re-transcription merges to dev, .github/workflows/deploy.yml runs npm ci and
npm run build and publishes the result to GitHub Pages on that push, so an updated QueryEngine
reference is live as soon as it lands on dev (see 7. Publishing). The build is the
only thing standing between the merge and the public page — and it proves the site compiles, not that
the page still matches the engine.
Periodic surveillance of new SDK operators does not belong to this flow; it is a dedicated reconnaissance, ADO-2349.
6. Open a Pull Request
Section titled “6. Open a Pull Request”- Branch off
devusing the naming conventiondocs/<short-description>(or the swarm branch convention if operating in a swarm run). - Add only the files you own or have been given permission to touch.
- Request a review from at least one person on the owning team. If the owning team is unclear, ask the Documentation team to route the review.
- Run
npm run build(astro build) locally and make sure it passes. No workflow runs on a pull request in this repository:.github/workflows/deploy.ymlis the only workflow and it triggers on pushes todev, so the one automated check —npm run build— runs after your merge, not before it. There is no separate frontmatter linter either: a missingtitleordescriptionfails the build itself. - Merge to
devafter approval. If the build then fails ondev, nothing is published until it is fixed (see 7. Publishing).
7. Publishing
Section titled “7. Publishing”xrmghost-docs is a standalone site. It is built with Astro/Starlight and published to GitHub
Pages by .github/workflows/deploy.yml, which runs npm ci and npm run build and deploys the
result on every push to dev.
- Once your PR merges to
dev, publication is automatic. There is no submodule pointer to advance and no sync script to run. - You do not need to take any action in
xrmghost-user-portal. - If the build fails, the deploy does not happen: the merged change is live only once
npm run buildsucceeds in the workflow.
Summary Checklist
Section titled “Summary Checklist”- Confirmed the correct product owner or reviewer path before editing
- File placed in the correct
src/content/docs/subfolder - File name is lowercase and hyphen-separated
- Frontmatter includes
titleanddescription - No fake content — used
> **TODO**:markers where content is missing - PR targets
dev, reviewer from owning team assigned -
npm run buildpasses locally - If the change touches the QueryEngine operator reference, followed 5.3 — snapshots replaced whole, provenance updated, page re-transcribed and reviewed by hand