Frontmatter and Build Rules
The documentation site has two kinds of expectations:
- Enforced rules — checked by
make pr-checks(and the equivalent CI gates). A violation fails the build and CI rejects the pull request. These are listed under each section below with an 🔒 Enforced badge. - Conventional rules — agreed by the authors and reinforced by review, but not mechanically checked. These carry a 🤝 Convention badge. Violating them is not a CI failure but is a review comment.
Both serve the same goal: keep the site readable by humans and automated agents (LLM assistants, MCP clients, search bots). The enforced rules cover the most consequential gaps; the conventional ones cover the rest.
Most rules are inexpensive to follow once you start from a template under about/templates/. When you copy a template you inherit the required frontmatter and the canonical section structure for free.
Frontmatter
Section titled “Frontmatter”Every Markdown or MDX page under src/content/docs/ carries a YAML frontmatter block. The schema lives in src/content.config.ts and is enforced by Astro at content-collection load time.
Required fields 🔒 Enforced
Section titled “Required fields 🔒 Enforced”| Field | Type | Constraint |
|---|---|---|
title | string | Starlight base; required |
description | string | Required, 40–300 characters, single sentence |
author | string | Required, non-empty |
The schema in src/content.config.ts is checked by Astro at content-collection load time, which make pr-checks runs via the preview build. A missing description (or one shorter than 40 / longer than 300 characters), or an empty author, fails the build with an InvalidContentEntryDataError. CI catches the same violation through the same path.
Recommended fields
Section titled “Recommended fields”| Field | Type | Notes |
|---|---|---|
tags | array of strings | Defaults to []; populate it |
domain | enum (see below) | Optional; aligns with the directory |
maturity | stub / draft / review / published / proposed | Defaults to published |
lastVerified | ISO date | Optional; the date a human last reviewed the page |
supersedes | path | Optional; points to an earlier page this replaces |
domain ∈ product, domain, system, vision, roadmap, process, technology, legal, decisions, about, notes.
The convention is to use maturity: published once the page is written and substantively complete. Pages do not need long stays at draft — the build does not care, but consumers of llms.txt and agents reading the site will treat published as the authoritative signal.
Style for description
Section titled “Style for description”The description field is the most consequential. It appears in:
<meta name="description">for search engines.- The curated
/llms.txtindex (when the page is promoted). /llms-small.txtand/llms-full.txt(where it routes retrieval).- Site search results.
Compose it as a single sentence (no newlines, no double quotes, no backticks):
- 80–200 characters is the sweet spot. The schema allows 40–300, but 80–200 captures the page without bloating the index.
- Lead with the noun phrase: “Reference for…”, “Specification of…”, “Playbook covering…”, “Index of…”. Avoid “This page describes…” and “A guide to…”.
- Capture what the page documents and (when relevant) for whom — a developer, an operator, an agent.
- Use US English spelling.
A few examples drawn from the corpus:
Cedar policy language reference covering core concepts, decision logic, and entity model used as the basis for the Arda Multi-Enterprise Authorization Model.
Operator runbook for sending email through the Free Kanban Tool Postmark server, covering token resolution, From-address constraints, SDK and curl recipes, and troubleshooting.
Bitemporal persistence model tracking valid time and transaction time to support historical queries, auditing, and corrections without data loss.
Body content
Section titled “Body content”No in-body # H1 🤝 Convention
Section titled “No in-body # H1 🤝 Convention”Starlight already renders the frontmatter title: as the page H1. A second # Heading in the body produces a duplicate visual H1 and confuses Markdown parsers. Start the body with ## Section, not # Title.
This is not currently enforced by make pr-checks — the build will succeed with an in-body H1 — but every existing page follows the rule and reviewers flag deviations.
Code fences carry a language tag 🤝 Convention
Section titled “Code fences carry a language tag 🤝 Convention”Every fenced code block should declare a language. Common tags in the corpus:
| Language family | Use tag |
|---|---|
| Shell sessions | bash |
| TypeScript / JavaScript | typescript, tsx, javascript |
| Kotlin | kotlin |
| JSON / YAML / TOML | json, yaml, toml |
| HTTP request / response | http |
| SQL | sql |
| Markdown samples (nested) | markdown |
| Prose / file paths / pseudocode | text |
Untagged fences (``` alone) degrade syntax highlighting and lose information for agents that route fenced content through language-specific tools. The convention is to use text for prose-like blocks rather than leaving the tag off. This is not currently enforced by make pr-checks; it is a review-time expectation.
PlantUML diagrams are paired with a textual summary 🤝 Convention
Section titled “PlantUML diagrams are paired with a textual summary 🤝 Convention”Agents rarely consume images, even SVG-rendered diagrams. Every PlantUML block should be preceded by a 1–3 sentence prose summary that captures the same semantic content the diagram conveys:
The sequence below shows the upload flow from the browser through the BFF to S3. The browser obtains a presigned URL, uploads directly to S3, then notifies the BFF on success.
```plantuml@startumltitle Upload flowactor Browserparticipant BFFparticipant S3Browser -> BFF: GET /upload-urlBFF --> Browser: presigned URLBrowser -> S3: PUT (presigned)S3 --> Browser: 200Browser -> BFF: POST /upload-complete@enduml```Not enforced by make pr-checks. See the PlantUML guide for additional styling conventions.
Internal links include .md 🔒 Enforced
Section titled “Internal links include .md 🔒 Enforced”Links between documentation pages must include the .md extension. The remark-resolve-md-links plugin rewrites them to the rendered URL at build time. Linking without the extension passes the dev server but fails the preview-base link checker that runs as part of make pr-checks (Lychee).
Anchors are preserved through the rewrite: [Section 3.2](../foo.md#section-32) resolves correctly.
MDX-specific constraints 🤝 Convention
Section titled “MDX-specific constraints 🤝 Convention”.mdx files are parsed as both Markdown and JSX, so a few Markdown idioms collide with JSX expectations. The conventions:
- Use
<table>HTML for non-trivial tables in.mdxfiles. Simple Markdown tables can work, but cells that contain|, JSX expressions, or multi-line content cause the parser to misalign rows. The homepageindex.mdxuses Markdown tables in the showcase section because the cells are simple — when in doubt or when a cell needs structure, switch to<table>. - No named HTML entities (
≥,×) — use numeric entities (≥,×) or direct Unicode. - No bare curly braces in prose — wrap
{foo}in backticks to disambiguate from JSX expressions. - Use
<Aside>instead of:::tipshorthand in.mdxfiles. The triple-colon admonition shorthand is the.mdconvention; in.mdximport and use the Starlight<Aside>component for consistency.
The full list of MDX gotchas is in the repo’s knowledge-base/mdx-gotchas.md.
Templates
Section titled “Templates”Start from a template before writing from scratch. Templates already model the required frontmatter, the canonical sections, and any per-artifact rules.
The catalogue is at about/templates/ — design documents, decision logs, runbooks, content pages, ADRs, user stories, and more. Each template’s own description tells you when to use it.
What the build checks
Section titled “What the build checks”There are two layers of automated checks. make pr-checks is the local gate you run before every push; CI runs the same gate plus a few GitHub-Actions-only checks that cannot live locally.
make pr-checks (local + CI)
Section titled “make pr-checks (local + CI)”Runs in order:
- Astro preview build — content-collection schema validation runs here. Missing or out-of-range
description, missingauthor, an unknownmaturityenum value, etc., all fail at this step with anInvalidContentEntryDataError. - Link checker (Lychee) — runs against the preview-base build (
/documentation/...). Catches internal links that omit the.mdextension or point at non-existent files. - Smoke tests (Playwright) — runs against the built site.
The cycle is fast (~30 seconds for an incremental build) and matches what CI runs for the same checks.
CI-only
Section titled “CI-only”These run in GitHub Actions and cannot be triggered locally:
changelog-check— verifies the pull request description carries a## CHANGELOGsection with at least one valid category, and that the diff does not includeCHANGELOG.mdunless themanual-changeloglabel is set. Workflow:.github/workflows/changelog-check.yaml.review-required-gate— enforces the CODEOWNERS /REVIEW-REQUIREDpolicy.- Build production / deploy — runs only on the merge-queue group event, not the PR head.
If a CI-only check rejects your PR, the fix is to update the pull request description (for changelog-check) or to ensure the right approvals are in place (for review-required-gate).
When the build catches you
Section titled “When the build catches you”The most common failures and how to fix them:
| Error | Fix |
|---|---|
description: Required or string-length error | Add or extend the description field in the page’s frontmatter |
author: Required | Add author: "<your name>" to the frontmatter |
maturity: Invalid enum value | Use one of stub / draft / review / published / proposed |
Link checker: Cannot find file … | Add .md to the internal link, or fix the relative path |
CHANGELOG.md change rejected by CI | Move the entry to a ## CHANGELOG block in the PR description and revert the file edit (or add the manual-changelog label if a hand-edit is genuinely required) |
Related
Section titled “Related”- Authoring guide overview — the starting point for new contributors.
- PlantUML guide — diagram syntax, summaries, and validation.
- Cross-site linking — when to link across sibling repos.
- Templates index — start from a template.
- Agent Access — how the same content is consumed by AI assistants and MCP clients.
knowledge-base/frontmatter-schema.md— repo-side notes (visible from a clone, not on the site) on the schema and backfill scripts.
Copyright: © Arda Systems 2025-2026, All rights reserved