<site id>.tree.yml
The navigation file of a declared site and locale pair, at content/<locale>/<site id>.tree.yml. The
"Codocation" tool window edits it visually; the format below is what lands in the file.
The physical file content/en/cdc.tree.yml contains the English tree, while its page entries
use logical paths such as pages/guide.md, without the physical content/en/ prefix. The
locale code is registered in the project-wide locales: catalog, and the pair is published only
when that code appears in sites.<siteId>.locales.
title: Product Documentation # required, reader-facing site name
description: Guides for using the product. # optional site summary
header: # links in the site header
- page: pages/pricing.md
- href: https://github.com/acme/product
type: github # draw the entry as a brand mark
title: GitHub # its tooltip and accessible name
- href: https://acme.com/signup
title: Get started
type: primary-button # draw it as a CTA button: primary is filled, secondary outlined
color: "#6c5ce7" # optional: the fill of a primary, the border of a secondary
toc: # the sidebar / table of contents
- page: pages/index.md
home: true # served at the site root; exactly one page may have it
- page: pages/getting-started.md
title: Start Here # optional label override; default = the page's own title
- section: # a named group, not a page; the key itself takes no value
id: guides # its stable identity, which locale trees match on
title: Guides # what the sidebar shows
collapsed: true # start collapsed in the sidebar
children:
- page: pages/guides/install.md
- page: pages/guides/deploy.md
- page: pages/reference.md
children: # child refs resolve relative to the parent page's directory
- page: reference/api.md
footer: # the four parts the theme paints, each in its own slot
nav: # plain link rows; same item forms as header
- href: https://acme.com/support
title: Support
social: # brand marks, each an ordinary record
- type: github
href: https://github.com/acme/product
legal: # the centered row above the copyright line
- title: Privacy
href: https://acme.com/privacy
copyright: © 2026 Acme Inc. # omit (or leave blank) for the built-in attribution line
Site metadata
title is required and is the only source of the locale's site name shown in the header, footer,
browser metadata, and generated artifacts. description is optional. Both fields are
localizable and therefore belong to the tree rather than codocation.yml.
TOC titles
The optional page-item title is a TOC-only label. Editing it changes the sidebar and navigation
text for that item and never changes the Markdown page title, frontmatter bundle, or rendered H1. A
valid title never produces an invalid-field diagnostic.
How a locale tree inherits
A locale's tree is a sparse overlay on the site's effective default language, resolved per field rather than per file. Every key it leaves out is inherited, and only the keys it writes are its own, so a German tree that translates two section titles is two sections long and takes everything else from English.
Membership merges by identity, not by replacement. Nodes are matched across languages by identity
alone, never by position: page: for a page, href: for a link, id: for a section, type: for
a social mark. Matching never crosses sections, and a node whose parent found no counterpart has
none either. A duplicated identity on either side makes both ambiguous, and they inherit nothing.
A list the locale does not mention inherits whole, and a locale that mentions some of a list still
inherits every entry it did not name - leaving a page out of a locale tree no longer excludes it.
One consequence is worth stating outright: a locale cannot point a link at a localized URL, because
changing href changes which node it is.
A locale may take ownership of one list's whole membership instead of just inheriting it, with a
boolean key written beside the list it governs: ownToc and ownHeader at the tree root, ownNav
inside footer:, and ownChildren beside the children of a section or a page entry - an external
link has no children, so it carries no such key. Absent or false leaves that list's membership
inherited, as above; true makes the merged list exactly the entries this file writes, in this
file's own order, so a default-language entry the file does not name is not in the list at all.
Detaching a list changes its membership and order and nothing else. An entry the file does name
inside a detached list still matches its default-language counterpart by identity and still
inherits every key it does not write itself. Detaching does not reach downward: a section or a page
with children of its own, sitting inside a detached list, keeps its own children inherited until it
carries its own ownChildren: true.
An empty list is still an inherited one on its own - writing an empty toc: with no ownToc: true
beside it inherits every entry the default language's table of contents has. Only the detach key
next to it makes the list genuinely empty.
ownSocial and ownLegal are reserved for footer.social and footer.legal and are not accepted;
those two stay identity-merged only, the same way described below.
An entry the locale does not want announced carries hidden: true there; the page still builds and
stays reachable at its own URL, but is left out of navigation, search, and every generated index for
that locale. An entry that is this language's own rather than a translation of anything carries
inherited: false instead - every item kind accepts it, it defaults to true, and it is a warning in
the default-language tree, where every item is already that language's own. An entry that claims a
translation and finds no counterpart is a warning, and inherited: false is how you answer it.
Hiding and dropping are different outcomes. hidden: true still builds the page; dropping happens
when detaching a list stops naming a page there and no other list of that locale - header, toc,
or footer.nav - names it either, so the page is not built for that locale at all. A page file the
locale had already translated that its merged tree no longer names anywhere becomes an orphan
(NAV_002).
A locale-only entry - one with no counterpart in the default language - is placed immediately after
the nearest preceding entry it shares the file with; write one bare identity line above it
(- page: intro) to anchor it in the middle of a list. Order otherwise always follows the
default-language tree: a locale that writes two matched entries in a contradicting order gets a
warning and the base order, because the written order cannot be honored without silently discarding
what the locale left unwritten.
A locale tree may take ownership of its own order instead, with one root key:
ownOrder: true
Illegal in the default-language tree. While present, this file's order - across toc, header,
footer.nav, footer.social and footer.legal, and every section's children - is the order, and
a base entry this file does not name is placed after its preceding named entry, or before its
following named one, or at the end when neither is named. Membership still inherits either way;
ownOrder only detaches order. The tool window writes this key itself the first time a drag, a
sort, or a locale-only insertion needs it - a hand-written ownOrder: true means exactly what it
says.
footer: merges social and legal by identity through the same walk as toc/header, so a
locale may translate one mark's tooltip while every other mark, and every legal link, still
inherits. copyright stays a plain scalar override.
Where a page's text comes from
Not from the tree. A page resolves from the requested locale's own file under pages/ when that
file exists, and from the site's effective default language when it does not. There is no marker for
it, because "does this entry translate one in the default language" and "where does this page's
markdown come from" are two different questions, and the tree answers only the first. A page with no
file in the requested locale is not a diagnostic: that is the ordinary state of an untranslated page
and of every single-locale project.
The older translation key, its excluded state and the reason field beside it are all rejected
outright.
Item forms
- Page:
page:with a canonical logical path underpages/when it has no ancestor page, whether it is at the root or inside sections. In that case, exactly one bare Markdown filename such asindex.mdis also accepted as a fallback forpages/index.md. Any descendant of a page resolves relative to the nearest ancestor page's directory, even through intervening sections, so thereference/api.mdchild above resolves topages/reference/api.mdwhen the parent ispages/reference.md. A childapi.mdunder a parent such aspages/guides/reference.mdwould resolve topages/guides/api.md. Optional keys:title(label override),home(site root marker),hidden(announced nowhere, still built and reachable),children(nested items), andinherited: false(this entry is this language's own, not a translation). - External link:
href:withtitle:. A header link may addtype:to draw it as a brand mark (one of the recognized brand names) or as a CTA:primary-buttonfor the filled button,secondary-buttonfor the outlined one, the same two names an inline[Text](url){button="primary"}uses on a page; omittingtype:draws a plain row.color:goes with a buttontype:and states your own shade where the theme's accent would stand, so it is the fill of a primary and the border of a secondary. - Section:
section:with no value of its own, plus the siblingsid:,title:andchildren:; sections group pages in thetocand may nest. Optionalcollapsed: true. Theidis the section's stable identity and must be unique in the file; thetitleis what readers see, so renaming a section leaves every other file pointing at it alone. - Social mark (
footer.social): a record oftype:(the brand, its identity),href:, and an optionaltooltip:(the accessible name; falls back to the brand's own name). A locale mark can state onlytooltip:and inherithref:from its default-language counterpart. - Legal link (
footer.legal): a record oftitle:,href:(its identity) and an optionalimage:(a project asset path drawn as a small<img>beside the label).
Rules validation enforces
- The default-language tree must declare
title,header,tocandfooter. It inherits from nothing, so it has to be complete; a locale tree may omit all four, which simply means the whole tree is inherited. inheritedis a WARNING in the default-language tree. In a locale tree, an entry with no counterpart in the default language is a WARNING untilinherited: falsesays it is this language's own.ownOrderis a WARNING in the default-language tree, where there is nothing to detach from.ownToc,ownHeader,ownNav, andownChildrenare each a WARNING in the default-language tree too (NAV_025), for the same reason.- A detach key written without the list it governs in the same file is a WARNING (NAV_026): with no list beside it the key detaches nothing, so that list stays inherited and the built site is unchanged.
- Two sections in one file may not share an
id. - Pair trees are required only for declared site memberships. A tree or sidecar for an undeclared pair is an ERROR and ignored; a locale directory absent from the root catalog is an orphan-locale ERROR and ignored.
- The root
titlemust be non-empty. - Only one page carries
home: true. headeris a flat list andfooter.nava flat list: no nested sections in either.footeris a map ofnav,social,legalandcopyright, not a list. The order between those four belongs to the theme, so no authored order can put a brand mark above a nav row; the order inside a slot is yours, or the default language's untilownOrder: truetakes it back.- An item is one thing:
page,section, orhref, never a combination.
