Skip to content
Machine Behavior

Site navigation and chrome

machinebehavior.io is one portal: "Machine Behavior" is the site, Inside is the portal within it. Every page carries the same top bar, breadcrumbs from Home to the page, and the same footer. The sections and their pages are defined once, in site/nav.yml; scripts/site_chrome.py writes the chrome of every page from that file.

Sections

SectionFront pagePages
Home/
Research/research/claims, experiments, objections, evidence, slips, case files, articles, man pages, terms, the continuous-conformity definition and the self-assessment
Inside/inside/Mission Control, services (one page per service, from services/*.yml), status, board, gate runs, tour, search
Docs/inside/docs/the space tree, from inside/docs/tree.json (written by scripts/build_docs.py)
Topics/topics/one hub per topic in site/topics.yml
Map/map/

/research/ is built by scripts/build_hubs.py from the same file: every research page in its group, with the description the page gives itself. The same script builds the topic hubs.

sections:
  - key: research
    title: Research
    url: /research/
    pages:
      - title: Claims ledger
        url: /claims/
      - group: Case files          # a sidebar heading; no page, no breadcrumb
        pages:
          - title: Running conjobs for AI
            url: /running-conjobs-for-ai/
  - key: inside
    title: Inside
    url: /inside/
    banner: true                   # the public-demo strip on app pages of this section
    pages:
      - title: Services
        url: /inside/services/
        auto: services             # one child per service, from inside/services/services.json

title is the name in the breadcrumbs and the sidebar. url is a root-absolute page path, or an anchor on a page (/inside/#dashboards), which appears in the sidebar but is not a page. legal holds the Impressum and privacy links for the footer; it stays empty until the business address exists (#10, #11).

The managed blocks

apply(html, rel) in scripts/site_chrome.py writes five blocks. Each sits between <!-- mb:NAME --> and <!-- /mb:NAME -->; everything outside the markers is page content.

BlockWhereWhat
headbefore </head>the design-system stylesheets, a JSON-LD BreadcrumbList and the page's JSON-LD graph
barafter <body>skip link, top bar (brand, sections, search), and on Inside and Docs app pages the demo banner
crumbstop of <div class="sheet"> (reading pages) or <main> (app pages)the visible breadcrumbs
sidebefore the sheet or <main>the section sidebar
footbefore </body>conformity line, page source and history, report an issue, legal links

A page that holds the markers keeps them where they are: the map puts its breadcrumbs and footer inside its panel. A page without them gets them at the anchors above. apply() also removes the chrome it replaces: the old research menu (<nav class="nav">), the old Inside bar and banner, and the old conformity line.

The footer links the page source. A generated page names its source in <meta name="mb-source" content="scripts/docs/eng/x.md">; a hand-written page is its own source.

Who calls it

PageHow it gets the chrome
Docsscripts/build_docs.py calls apply() for every page it writes
Services and statusscripts/build_inside.py calls apply(), then runs the whole-site pass
Slipsscripts/slips_page.py calls apply()
/research/scripts/build_hubs.py calls apply()
Hand-written pagespython3 scripts/site_chrome.py
/conformity/rendered by the gate on every run; the deploy job runs scripts/site_chrome.py before the upload

Commands

python3 scripts/site_chrome.py           # write the chrome on every page, then report
python3 scripts/site_chrome.py --check   # write nothing; exit 1 if a page differs, a page is outside the tree,
                                         # or a page in the tree is missing from sitemap.xml

The report lists orphans (an index.html outside the tree), pages in the tree without a file, pages missing from sitemap.xml, sitemap URLs outside the tree, and pages missing from llms.txt (a warning).

Research and Inside pages carry the section sidebar (SIDEBARS in scripts/site_chrome.py): every page of the section in the order of site/nav.yml, groups as headings, Services as a disclosure open on a service page, the current page marked. From 1100 px it is a sticky column of 264 px beside the content; below that it is a disclosure above the content, closed on load by /inside/bar.js. Docs pages keep the space tree from scripts/build_docs.py. See ADR-0022.

Topics

site/topics.yml holds the topics and the rules that select their members: hand-written and Inside pages, docs labels and spaces, tag pages on the map, words in Substack titles, and board labels or words. scripts/build_hubs.py builds the hubs at /topics/<key>/, the index at /topics/ and /topics/topics.json, then writes the chrome of every page again so the Topics block in each sidebar marks the topics that list the page. The docs sidebar holds the block as <!-- mb:topics --><!-- /mb:topics -->. See ADR-0023.

Build order: build_docs.py, build_inside.py, build_hubs.py; then site_chrome.py --check.

Structured data

The head block also holds one JSON-LD graph per page: Stefan Coetzee as Person (from site.person), the site as WebSite with its search, the page as Article, TechArticle, CollectionPage or WebPage with headline, description and dates, and DefinedTermSet on /terms/ and /continuous-conformity/ with the wording on the page. A research page's publication date sits in site/nav.yml as published. --check fails on a JSON-LD block that does not parse. See ADR-0027.

Layouts

Two layouts under one brand. The reading layout keeps the serif column of the research pages (/style.css, <div class="sheet">, teal accent). The app layout keeps the portal look of Inside, Docs and the map (amber accent). apply() picks the layout from the stylesheet the page loads and sets mb-read or mb-app and mb-s-<section> on <body>. Light and dark follow the system setting in both layouts. The styles are in /design/: tokens.css (colour, type, spacing; the older page variables map onto it), chrome.css (bar, breadcrumbs, sidebars, footer, layouts) and components.css (page header, pills, cards, panels, tables, lists). See ADR-0025.

Hand-written pages show their owner and the date from sitemap.xml beside the breadcrumbs; generated pages carry their own byline.

Related: Top bar and search, Add a page to machinebehavior.io, ADR-0021.

Built from scripts/docs by build_docs.py.