SYSTEM / CONTENT

Content format — MD page definitions

Updated 08/2026

The content of this site lives in Markdown files inside the repository — no database, no CMS, no admin interface. The binding shape is set by ADR-0011 (content schema) and ADR-0012 (language mutations). The build reads the files, validates them and renders static HTML. An unknown field, a missing required value or a typo in a control prefix stops the build, so the mistake cannot be published.

Where the content lives

  • content item — content/ygg/explore/<slug>/cs.md and en.md
  • static page — content/ygg/pages/<slug>/cs.md and en.md
  • item assets — content/ygg/explore/<slug>/assets/

The directory is the slug, the file name is the language. Neither is written in the frontmatter — both are reported errors. Mutations are paired by directory: without en.md the English address simply does not exist. A translation is never faked with Czech text.

Item frontmatter

The required fields are title, type, topics, tags and date.

  • type — one of eight values guide, troubleshooting, reference, explainer, analysis, note, link, project. It drives the icon, the ordering and the address: a guide lives at /en/guide/<slug>/, a problem at /en/problem/<slug>/.
  • topics — a controlled vocabulary; a free keyword belongs in tags.
  • status — a controlled vocabulary shown in the item panel.
  • date, updated, verified, published, dataTo — always ISO YYYY-MM-DD. The MM/YYYY shape is a display format only, never a storage format.
  • optionally summary, desc, hero, toc, numbering, scope, environment, difficulty, level, duration, reading, prereqs, sources, sourcesCount, related, callout, calloutLabel, url, source, from, stack, pub, featured, order, assets, sections.
  • draft: true keeps an unfinished item out of the build, the site map, the feeds and search.
  • redirect_from is required as soon as a published address changes; the build turns it into a redirect.

The fields decide, not the record type: whatever is not filled in is not rendered. An empty value, null and an em dash all mean the same thing — not filled in.

Item body

The body is Markdown extended by a closed set of control prefixes:

  • ## Heading is a section, ### Heading a subsection; the anchor comes from the heading slug
  • nav: a short section label for the side contents — allowed only right after a heading
  • command: a command line
  • note: and warning: a note and a warning
  • - a bullet, -! an accented bullet, 1. an ordered list
  • a fenced code block; the language output turns it into an output block rather than input
  • | key | value | is a two-column table; when the keys are dates it renders as a timeline
  • ![description](file.png) an image — the alt text is required, a decorative image does not belong in content

A prefix outside this list is an error, not text to render. The typo waring: would otherwise be quietly published as a paragraph.

Static page

A static page comes in two shapes and both are valid:

  • reading — like this page: the frontmatter carries kicker, title, optionally lead and updated, and the content is entirely in the body
  • structured — like About, Work or Public: the sections field in the frontmatter drives the order and shape of the bands, and long texts sit in the body behind a <!-- section: id --> marker

The section types are text, grid, list, index, states, steps, chips, keyvals, stat, kontakt, callout and featured-projects. The last one is never filled in by hand — it is derived from the project collection. Most sections keep their data in items; keyvals keeps it in groups and chips may add links below the badges. A section without its data would be an empty band, so validation rejects it. An internal target is addressed in a section by linkRoute (an id from the route table) and a list item by its slug; a finished path does not belong in content, because the route table owns it and the build adds the language.

The two shapes are never mixed. A heading in the body of a structured page would be a second, unmanaged structure next to sections, and validation rejects it.

Safety and checks

Raw HTML is limited to details, summary, figure, figcaption, abbr, mark, kbd, sub and sup, with the attribute open only on details and title only on abbr. Anything else is printed as text, not as markup.

Assets are recorded in the assets field with path, origin, creator and license; third-party material also with source_url. The path must be relative and free of ...

The whole tree is checked by make content-check — the same validation the build uses. An error is reported with the path to the field, not just the file name.