Web na https://majordomus.dev/ je projekce tohoto repozitáře. Je postaven tak, jak Majordomus žádá projekty, aby stavěly vlastní instrukční soubory: jeden kanonický zdroj, generované výstupy a kontrola, která selže, když se oba rozejdou.
Účel
Nechat návštěvníka za zhruba dvě minuty pochopit, co Majordomus je, co zaručuje, co je jen poradní, co není postaveno a jak začít, aniž by jakákoli věta na webu byla udržována odděleně od repozitáře, který ji podpírá.
Kanonické zdroje
| vrstva | vlastní | žije v | upraveno ručně |
|---|---|---|---|
| pravda o produktu | schéma politiky, profily, instrukce pro workery, shellové CLI | share/skeleton/**, bin/majordomus, lib/**, share/commands.yaml | ano |
| spustitelný soubor v Rustu | každá schopnost se svými schématy, expozicemi, stabilitou, proveniencí, měřením a politikou cache; moduly; příkazová řádka s příklady každého příkazu | deklarace capability! a module! pod apps/majordomus-cli/src/capability/builtin/, apps/majordomus-cli/src/cli.rs (clap pro strukturu, cli::EXAMPLES pro příklady) | ano |
| vyprávění spustitelného souboru | čím crate je, co vlastní a co odmítá; discovery, transporty, vedlejší efekty, architektura | apps/majordomus-cli/README.md, docs/CAPABILITIES.md, docs/MCP.md | ano |
| důkazy z měření výkonu | politika regrese a přijaté základy | .ai/repo/benchmarks/rust/policy.yaml, .ai/repo/benchmarks/rust/baseline.<platform>.json | politika ano; baseline od majordomus bench baseline update |
| projekce registru | dokument OpenAPI, manifest registru, reference schopností, modulů a měření výkonu, příkazová řádka a manifest celé generované sady — každý dokument v každém kódování, v němž je commitnut | docs/generated/** (artifacts.md je jeho generovaný index) | nikdy — majordomus generate |
| datová sada registru | vše, co web vykresluje o spustitelném souboru: deskriptory, moduly, příkazová řádka, povrchy MCP a HTTP, měření výkonu, index | site/data/registry/registry.json | nikdy — majordomus generate site |
| veřejný příběh | co to je, proč, jak, co to odmítá | README.md, docs/*.md | ano |
| tvrzení | každá schopnost se stavem, zdrojem, implementací, testem | docs/CLAIMS.yaml | ano |
| marketingový text | pozicionační věty hrdiny, úvody sekcí, popisky tlačítek; žádná tvrzení o schopnostech, žádná čísla, rozpočet 80 řádků | site/data/marketing.toml | ano |
| navigace | záměry, jejich položky rozbalovací nabídky a href a trasy, které se přesunuly ([[redirects]], vykreslené jako aliasy Zola) | site/data/nav.toml | ano |
| detail tvrzení | co každé tvrzení znamená, jak funguje, jak ho vidět, co nepokrývá, proč existuje | docs/claims/<id>.md | ano |
| funkce produktu | jeden soubor na funkci: odkazy jmenující, z čeho se skládá, a redakční rozhodnutí, která nelze odvodit; každá plocha, počet a routa vedle toho se odvozuje (docs/PRODUCT.md, ADR 23) | .ai/repo/features/<id>.md | ano |
| případové studie | okamžiky rozpoznání, každý s háčkem pro úvodní stránku ve front matteru | site/content-src/why/*.md | ano |
| skills | dovednosti repozitáře, každá v jednom adresáři; web čte katalog, který lib/skills.sh odvozuje ze zdrojové třídy skill | .ai/repo/skills/<id>/SKILL.md | ano |
| referenční vykreslení | reprezentativní Markdown pro vizuální validaci | site/content-src/render-test.md | ano |
| odvozená data | stabilní JSON, který šablony čtou | site/data/generated/*.json | nikdy |
| smlouvy adresářů vrstvy | každý adresář .ai/, smlouva, kterou nese, nebo ta, která ho vyjímá, a počty | site/data/generated/context.json (z majordomus context list --json) | nikdy |
| odvozený artefakt vydání | matice tvrzení jako Markdown | docs/SITE_CLAIMS.md | nikdy |
| odvozený obsah | kanonický Markdown s generovaným front matter; jedna stránka na každý profil, tvrzení, stav, odpovědnost, příkaz, doktrínu, případ užití, aplikaci, milník, úkol, případovou studii, dovednost, modul a schopnost | site/content/{docs,profiles,guarantees,supervises,commands,doctrines,use-cases,applications,plan,why,registry,skills}/, render-test.md, architecture.md | nikdy |
| odvozené trasy a odkazy pro spustitelný soubor | jedna routa na modul a schopnost, stránky spustitelného souboru, kotva API, zdroj na GitHubu, tvrzení připojená ke každému povrchu | site/data/generated/executable.json | nikdy |
| nativní příkazová řádka, jak ji web vykresluje | strom příkazů zploštěný, každý příkaz se svou trasou, použitím, argumenty, potomky a provedenými příklady | site/data/generated/cli.json (z docs/generated/cli.json, přes scripts/lib/cli-site.jq) | nikdy |
| provenience sestavení | commit, jeho čas a čistota, vstupní hash webu, otisky registru a indexu a každý složený povrch s commitem, který deklaroval jeho producent | site/data/build.json, poskytováno jako /build.json | nikdy — scripts/site-build, necommitováno |
| reference crate | stránky rustdoc apps/majordomus-cli, složené v /rustdoc (RUSTDOC.md) | target/web/rustdoc/, s surface.json, který deklaruje, z čeho byl sestaven | nikdy — scripts/rust-check --doc, necommitováno |
| prezentace | Šablony Zola a komponenty Tera 2 | site/templates/** | ano |
| položka stylu | direktivy Tailwind v4 + Flowbite v4 | site/tailwind.css | ano |
| chování | přepínač motivu, prohlížeč diagramů, komponenta grafu | site/theme.js, site/diagrams.js, site/charts.js | ano |
| výstup | statický web | site/public/** | nikdy |
Na co musí umět odpovědět publikující klon
Web odkazuje na repozitář na jeho forge a scripts/ci/link-check tyto odkazy rozhoduje proti gitu, nikoli po síti: commit/<sha> a compare/a...b se rozřešují v historii, releases/tag/<t> a tree/<tag> ve značkách. Klon, který je nedostal, takový odkaz rozhodnout nemůže. Pak musí odmítnout, nikoli hádat — a scripts/site-check počítá odmítnutí jako selhání, takže publikace se zastaví.
To není hypotetická cena. Mezi 2026-09-14 18:34 a 2026-09-15 00:0x deploy dělal checkout do hloubky 1, což zkracuje historii a nestahuje žádné tagy. Šest odkazů na v0.3.1, v0.5.0 a v0.6.0 — tagy, které existují a nesou publikované releasy — bylo hlášeno jako neexistující, 2302 odkazů na commity nešlo rozhodnout, publish bylo při každém běhu přeskočeno a živý web zůstal na 8cf457000 sedm hodin, zatímco master postoupil o tři merge. Každá kontrola byla po celou dobu zelená, protože se nikdo neptal, zda je web aktuální.
Požadavek je tedy deklarován, nezapsán do workflow:
# .ai/repo/ci/pages.yaml
deploy:
checkout:
history: full # renders as fetch-depth: 0
tags: required # actions/checkout fetches none at a shallow depth| co | kde |
|---|---|
| požadavek | deploy.checkout v .ai/repo/ci/pages.yaml |
| hloubka, kterou implikuje | scripts/pages checkout — vypíše 0 |
| klon, který běh dostal | scripts/pages checkout --verify — kód 10, když nemůže rozhodnout o refu |
| pracovní postup držený modelu | test/cases/97_pages_fast_path.sh |
Workflow je nad tím adaptér, stejně jako je jeho blok paths: adaptér nad scripts/pages paths. Změna toho, co publisher potřebuje od svého klonu, je úprava modelu a nikde jinde: hloubku, ověření i test z něj čtou. Test, který by tvrdil fetch-depth: 0 doslova, by držel jednu záplatu na místě; případ porovná obojí a selže, když se rozejdou, ať se pohnulo kterékoli z nich.
--verify běží v úloze deploye hned po checkoutu, takže runner, který deklaraci nectí, tam selže s uvedením hloubky — místo o tři kroky později uvnitř link-checku, kde se problém checkoutu jeví jako vada odkazu.
Když zveřejnění selže: naplánovaný opakovaný pokus
Běh spuštěný pushem, který selže, nechá web tam, kde byl, a nic se neptá znovu. 2026-09-14 stál web sedm hodin, zatímco selhával každý běh. Proto .github/workflows/pages.yml běží i na hodinách, trigger.schedule v .ai/repo/ci/pages.yaml, každých třicet minut — okno, podle kterého posuzuje scripts/ci/pages-check (OWED_AFTER, 1800 s); rozvrh pomalejší než okno nemůže zaznamenat, co okno nazývá dlužným. test/cases/97_pages_fast_path.sh drží cron workflow na modelu.
Naplánovaný běh se zeptá, než pracuje, v malé vlastní úloze (owed):
| state | náprava | běh končí |
|---|---|---|
| web je aktuální | žádné; nic jiného neběží | zelená |
| gh-pages nenese web trunku | joby rustdoc a deploy běží jako při pushi | červená |
| gh-pages je v pořádku, vlastní build GitHubu skončil chybou | scripts/pages rebuild | červená |
Červená je záměrná: běh opravil závadu, kterou běh spuštěný pushem neměl nechat, a oprava bez hlášení by skryla závadu, která se opakuje každých třicet minut. Job intervention říká, co bylo dlužno a co se udělalo.
Přestavba je jiná akce než opětovné nasazení. Nasazení identického stromu nic nezmění, když selhal builder GitHubu, a žádost o sestavení předběhne rozběhnuté sestavení: dotaz během sestavování GitHubem toto sestavení zabije. scripts/pages rebuild se proto ptá, jen když sestavení commitu skončilo chybou a nic se nesestavuje, čte tento stav přes scripts/pages built --porcelain (jediného čtenáře), končí exitem 12 bez dotazu, když stav nelze přečíst nebo sestavení běží, a po dotazu stav přečte znovu. „gh-pages je správně“ se měří, ne předpokládá: job owed zvolí přestavbu, jen když je commit nejvyšší úrovně z build.json gh-pages commitem kmene, který běh checkoutoval. Chybné sestavení staršího stromu — push nasazení, které selhalo před publikací, nad sestavením, které také selhalo — se nasadí, protože jeho přestavba by při každém běhu znovu publikovala zastaralý web. test/cases/625_a_rebuild_is_asked_only_when_it_helps.sh drží každé z toho, to poslední tím, že spouští nápravný krok samotného workflow proti oběma stromům.
Pipeline projekce
Dva generátory, jeden graf. Spustitelný soubor v Rustu promítá svůj vlastní registr; generátor webu promítá kanonické soubory a spotřebovává projekce spustitelného souboru přes jednu strojově čitelnou hranici, docs/generated/registry.json (a openapi.json); Zola vykresluje šablony nad tím, co zapsaly oba. scripts/derive spouští fáze v pořadí, scripts/derive-check prokazuje commitnutý výsledek a žádná fáze nečte svůj vlastní výstup.
flowchart TB
subgraph canonical
R[capability! and module! declarations, src/cli.rs with cli::EXAMPLES]
K[share/kinds.yaml, schemas, providers, policy]
D[README, docs/*.md, docs/claims, CLAIMS.yaml, RESPONSIBILITIES.yaml]
C[share/commands.yaml, use-cases.yaml, applications.yaml]
P[.ai/repo/project, rules, benchmarks]
end
subgraph stageA[stage A · majordomus generate, code only]
GA[docs/generated: openapi, registry, capabilities, cli, modules/*.md — json+yaml+md as each document is committed · share/allow/*.txt · AGENTS.md, CLAUDE.md]
end
subgraph stageB[stage B · scripts/generate-site-data]
GB[site/data/generated/*.json · site/content/** · docs/SITE_CLAIMS.md, PLAN_STATUS.md]
end
subgraph stageC[stage C · majordomus generate, over the index]
GC[site/data/registry/registry.json · docs/generated/benchmarks.* · docs/generated/artifacts.*]
end
subgraph build[scripts/site-build]
Z[zola + Tailwind → site/public · build.json]
end
R --> GA
K --> GA
D --> GB
C --> GB
P --> GB
GA -->|registry.json, openapi.json, cli.json| GB
R --> GC
P --> GC
GB -->|the derived documents are objects of the index| GC
GB --> Z
GC --> Z
| fáze | generátor | čte | zapisuje | kontroluje |
|---|---|---|---|---|
| A | majordomus generate | deklarace v Rustu, share/, politika a šablony poskytovatelů | docs/generated/{openapi,registry,cli}.{json,yaml}, docs/generated/{capabilities,cli}.md, docs/generated/modules/*.md, share/allow/*.txt, bootstrapy poskytovatelů | majordomus generate --check |
| B | scripts/generate-site-data | každý kanonický soubor (--inputs je vypisuje) a registry.json a openapi.json fáze A | site/data/generated/*.json, site/content/**, docs/SITE_CLAIMS.md, docs/PLAN_STATUS.md | scripts/generate-site-data --check (podle hashe vstupu) |
| C | majordomus generate | deklarace v Rustu a index vrstvy, který nyní obsahuje dokumenty, jež zapsala fáze B | site/data/registry/registry.json, docs/generated/benchmarks.{md,json,yaml}, docs/generated/artifacts.{json,yaml,md} | majordomus generate --check |
| build | scripts/site-build | fáze B a C, šablony, aktiva a artefakt každého publikovaného statického povrchu, který docs/generated/web.json jmenuje | site/public/** (s každým takovým povrchem složeným na jeho mountu), site/data/build.json, site/static/build.json | scripts/site-check, scripts/site-probe |
Hranice mezi spustitelným souborem a webem jsou data, v obou směrech čtení: generátor webu čte manifest registru kvůli id, z nichž dělá route, a nikdy neparsuje Rust; šablony čtou dataset registru pro každý fakt o schopnosti a žádný neopakují; spustitelný soubor o Zole neví nic. Manifest je projekce používaná jako rozhraní mezi fázemi, ne druhá pravda: schopnost existuje na jednom místě a generate --check odmítne manifest, který už neříká to, co deklarace.
Proč fáze C existuje: dataset vypisuje každý objekt vrstvy s jeho velikostí a odvozené dokumenty, které zapisuje fáze B, jsou objekty vrstvy, takže dataset se odvozuje po nich. Výstupy fáze C nečte nic než sestavení webu, takže graf nemá cyklus a druhé scripts/derive na čistém stromě nic nezmění — git status zůstane prázdné, což test/cases/51_derived_artifacts_committed.sh a kritérium release vyžadují.
scripts/generate-site-data přečte každý kanonický vstup, jednou ho normalizuje a zapíše:
| soubor | z | co |
|---|---|---|
project.json | bin/majordomus, README.md, LICENSE | název, verze, slogan, licence, příkazy, návratové kódy |
profiles.json | share/skeleton/profiles/*.yaml | každý profil, každé pole |
policy.json | share/skeleton/policy.yaml | politika jako struktura plus surový text |
capabilities.json | docs/CLAIMS.yaml | každé tvrzení; generátor selže na chybějící cestě nebo na netestovaném zaručeném tvrzení |
commands.json | share/commands.yaml, docs/CLI.md, testovací případy | každý shellový příkaz s jeho sémantikou, vyprávěním a důkazy |
catalogue.json | .ai/repo/use-cases/, .ai/repo/applications/ | případy užití a aplikace, křížově odkazované |
doctrines.json | balíčky pravidel | každá doktrína s jejím řetězcem vynucování |
plan.json | .ai/repo/project/ | milníky, úkoly, graf závislostí, odvozený stav |
openapi.json | docs/generated/openapi.json | HTTP API v podobě, kterou vykreslují api.html a api-tag.html, s jednou stránkou, na které je publikována každá operace a schéma (scripts/lib/openapi-site.jq) |
artifacts.json | docs/generated/artifacts.json | vlastní manifest generátoru — jen deklarace, nesoucí schema: 1 jako každý jiný soubor onoho adresáře s id schématu samotného manifestu pod manifest_schema, přesunutý pod site/data/, aby ho registry-artifacts.html mohl načíst; nic se nepřidává a v šabloně není jmenován žádný soubor. Velikosti a hashe se zahazují: dva subjekty manifestu zapisuje fáze C, takže kopie, která by je nesla, by nikdy nekonvergovala s fází B |
executable.json | docs/generated/registry.json, capabilities.json | jedna trasa na modul a schopnost, stránky spustitelného souboru, kotvy API, zdroje na GitHubu, tvrzení připojená ke každému povrchu cestou jejich implementace (scripts/lib/executable-site.jq) |
lifecycle.json | lib/finish.sh, share/skeleton/ai/repo/workflows/task-lifecycle.md, share/standard/majordomus/ | slovník výsledků, štítky divergence, kroky životního cyklu, deset principů (pravidla označená principle) |
diagrams.json | soubory výše | Zdroj Mermaid promítnutý z dat |
readme.json | README.md | sekce, které úvodní stránka vykresluje, podle nadpisu; přejmenovaný nadpis shodí build |
docs.json | docs/README.md | index dokumentace |
source.json | vstupy | verze, hash vstupu, verze generátoru, seznam vstupů; žádný commit (viz původ sestavení) |
site/content/docs/*.md se zapisuje z docs/*.md s generovaným front matter, odkazy přepsanými na trasy webu a celým tělem obaleným blokem Tera raw, aby Tera nikdy nešablonovala kanonický Markdown. Samotný tag zde nelze vypsat: doslovný uzavírací tag raw v kanonickém dokumentu by ukončil obal, který projekce kolem něj staví. site/content/registry/executable.md je apps/majordomus-cli/README.md přes tutéž projekci.
Odvozené soubory, klasifikované
| třída | co | příklady | pravidlo |
|---|---|---|---|
| kanonické | autorské, jediné místo, kde fakt žije | deklarace v Rustu, share/*.yaml, docs/*.md, docs/CLAIMS.yaml, .ai/repo/**, šablony, nav.toml, marketing.toml | upraveno ručně |
| odvozeno, commitnuto | projekce, kterou recenzenti vidí na GitHubu a CI ji porovnává se zdroji | docs/generated/**, share/allow/**, AGENTS.md, CLAUDE.md, site/data/generated/**, site/data/registry/**, docs/SITE_CLAIMS.md, docs/PLAN_STATUS.md | regenerováno pomocí scripts/derive, commitnuto se změnou, která ho posunula; scripts/derive-check odmítne drift |
| odvozeno, jen build | přestavěno při každém sestavení, nikdy necommitováno | site/content/{docs,registry,commands,...}/, site/static/{app.css,js/,openapi.json,build.json}, site/data/build.json, site/public/**, target/web/rustdoc/ | ignorováno gitem; scripts/site-check dokládá vlastní pojistky sestavení (13e, 13a) a že každý složený povrch patří tomuto sestavení (13m) |
| lokální, efemérní | stav tohoto checkoutu | .ai/local/**, apps/majordomus-cli/target/ | nikdy zdroj čehokoli, co web zobrazuje |
Generátor je vstup a v tabulce není
Každý řádek výše klasifikuje soubor. Klasifikace je neúplná jedním způsobem, který už tomuto repozitáři způsobil o vlásek: odvozené soubory jsou projekcí kanonických zdrojů tak, jak je čte jeden spustitelný soubor, a ten spustitelný soubor není soubor ve stromu. Dva buildy téže deklarované verze mohou promítnout různé registry.
Spustitelný soubor půjčený z jiného worktree — přes MAJORDOMUS_BIN, čímž se relace vyhne desetiminutovému rebuildu — je tedy třetí vstup a nevhodný selže tím nejhorším možným směrem: ohlásí strom jako zastaralý a vypíše nápravu, která regeneruje, a regenerace přepíše každý dokument podle modelu, který strom už nemá. 2026-09-10 tak zmizelo asi 9 700 řádků z docs/generated/changelog.json a příkaz skončil s nulou.
Než začnete derivovat spustitelným souborem, který jste právě nepostavili:
env -u MAJORDOMUS_SHARE "$MAJORDOMUS_BIN" generate --check # must say: in sync
a po každém odvození, před commitem:
git diff --stat -- docs/generated site/data # mass deletion is corruption
project.a-tool-that-cannot-match-the-tree-refuses je pravidlo; ochrana, která ho vynucuje, žije ve spustitelném souboru, takže platí pro každého volajícího, ne jen pro jeden skript.
Kde to upravím?
| Chci změnit | upravit | nikdy needitovat |
|---|---|---|
| titulek, popis, schéma, stabilita, tagy, měření výkonu nebo politika cache schopnosti v Rustu | jeho deklarace capability! pod apps/majordomus-cli/src/capability/builtin/ | docs/generated/**, site/data/registry/registry.json, jakákoli stránka /registry/ |
| jak je schopnost vystavena (nástroj MCP, zdroj, trasa HTTP, cesta CLI) | exposure téže deklarace | docs/generated/openapi.json, /docs/api/, /registry/mcp/ |
| název, popis nebo stabilita modulu | jeho deklarace module! | docs/generated/modules/*.md, /registry/modules/ |
| nativní příkazová řádka: příkaz, argument, výchozí hodnota, množina hodnot | deklarace clap v apps/majordomus-cli/src/cli.rs | docs/generated/cli.md, docs/generated/cli.json, site/data/generated/cli.json, /registry/cli/, /docs/cli/** |
| příklad nativního příkazu, nebo přidání příkazu, který žádný nemá | cli::EXAMPLES ve stejném souboru, vedle deklarace | příklad zapsaný do šablony, stránky nebo cli.md: stránky vykreslují vektory argumentů, které testy crate provádějí |
| prahy regrese měření výkonu | .ai/repo/benchmarks/rust/policy.yaml | tabulka politik na /registry/benchmarks/ |
| přijatý základ | majordomus bench baseline update na platformě, kterou měří | baseline JSON ručně |
| čím spustitelný soubor je, co vlastní, co odmítá; objevování; transporty; vedlejší účinky | apps/majordomus-cli/README.md | /registry/executable/ |
| kategorie shellového příkazu, fáze, čtení, zápisy, syntaxe, exit kódy | share/commands.yaml (sémantika) a docs/CLI.md (vyprávění) | commands.json, /commands/<name>/ |
| případ užití nebo aplikace | .ai/repo/use-cases/, .ai/repo/applications/ | catalogue.json, jeho trasa |
| tvrzení | docs/CLAIMS.yaml a docs/claims/<id>.md | capabilities.json, docs/SITE_CLAIMS.md, /guarantees/ |
| doktrína | soubor pravidel pod .ai/repo/rules/ nebo vendorovaný balíček | doctrines.json, /doctrines/ |
| milník nebo úkol | .ai/repo/project/** | plan.json, docs/PLAN_STATUS.md, /plan/ |
| profil, schéma politiky | share/skeleton/** | profiles.json, policy.json |
| druh nebo schéma | share/kinds.yaml, share/schemas/ nebo .ai/repo/knowledge/ pro tento repozitář | share/allow/*.txt, tabulka druhů |
| provider se zavádí | .ai/repo/policy.yaml, šablony poskytovatelů | AGENTS.md, CLAUDE.md, GEMINI.md |
| jak stránka vypadá | site/templates/**, site/tailwind.css | site/data/generated/** pro usnadnění života šablony |
| jaké stránky má sekce spustitelného souboru nebo jak se k jeho povrchům připojují tvrzení | scripts/generate-site-data, scripts/lib/executable-site.jq | seznam rout v šabloně nebo v nav.toml |
| redakční navigace | site/data/nav.toml — záměry a jejich pevné stránky | položka na modul nebo schopnost: tyto routy vyčísluje generátor a site-check odmítne takovou, která je zde napsána |
| slova domovské stránky | site/data/marketing.toml | číslo, slovo tvrzení |
Po jakékoli úpravě v levém sloupci: just derive, projděte diff odvozených souborů, just derive-check, commitněte obojí společně.
Vykreslování Markdownu
Kanonický Markdown musí zůstat čitelný na GitHubu, takže web používá jen syntaxi, kterou GitHub vykresluje nativně. scripts/lib/project-markdown.awk promítá tři nativní konstrukce GitHubu do komponent webu, jen na odvozené kopii:
| v kanonickém souboru | na webu |
|---|---|
ohrazení ```mermaid | <pre class="mermaid">, pojmenovaný, propojený a vybavený ovládáním při sestavení, kreslený na straně klienta v prohlížeči (DIAGRAMS.md); zdroj zůstává viditelný i bez JavaScriptu |
> [!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION] | Upozornění Flowbite |
| tabulka s rourami | zabaleno do overflow-x-auto, aby se široké tabulky posouvaly uvnitř svého kontejneru |
Vše ostatní je renderer Markdownu Zola uvnitř kontejneru Flowbite Typography (format dark:format-invert): nadpisy s kotvami, seznamy, seznamy úkolů, poznámky pod čarou, citace a zvýrazňování syntaxe na základě tříd ([markdown.highlighting] style = "class", témata ayu-light a ayu-dark). Zola zapisuje dva stylesheety témat do site/public/; scripts/site-build tmavý z nich omezuje pod .dark, aby jej vybíral tmavý režim založený na třídách. site/content-src/render-test.md vyzkouší každý konstrukt a nikam nevede žádný odkaz.
Mermaid
Na straně klienta, z připnutého balíčku npm, při buildu vendorováno do static/js/mermaid.min.js. Zvoleno místo SVG v době buildu, protože Mermaid CLI potřebuje v CI bezhlavý prohlížeč a web musí zůstat reprodukovatelný jen z bash, Node a Zola. Žádná stránka nenačítá build značkou script: site/diagrams.js je odložen a načte ho jednou, až je stránka naparsována. Inicializuje se s securityLevel: 'strict', barvy bere z designových tokenů stránky a při změně motivu kreslí znovu. Čtyři diagramy se promítají z dat, nikdy se nekreslí ručně: životní cyklus úlohy ze slovníku výsledků, graf od politiky k instrukčním souborům z projekcí politiky, pipeline webu ze vstupního seznamu generátoru a jádrový model z README. Selhavší diagram nechá viditelný svůj zdroj a nikdy nerozbije stránku.
Po Zole scripts/site-build spustí scripts/lib/diagrams.mjs nad sestavenými stránkami: každý diagram dostane id (diagram-<name>), seznam svých uzlů, nástrojovou lištu prohlížeče a seznam odkazů odvozených z identit v site/data/generated. Prohlížeč, schéma adres a komponenta grafu, která kreslí tabulku, jež stránka už vykresluje, vendorovaným buildem Apache ECharts, jsou popsány v DIAGRAMS.md (ADR 0152).
Struktura Zola
site/
config.toml base_url, class-based highlighting, heading anchors, footnotes
content/ _index and one stub per page; docs/ and render-test.md are generated
content-src/ hand-written pages that get the same projection as docs
templates/
base.html head, theme-before-paint, navbar, footer, Flowbite init, Alpine
components.html Tera 2 components: badge, code, card, section_head, diagram
index.html homepage: the business hero, then the sections, all from generated data
page.html standalone page with breadcrumb and Typography body
docs-section.html /docs/ index from the section's pages
docs-page.html document with sidebar navigation
profiles.html policy.html guarantees.html getting-started.html architecture.html
404.html
partials/ navbar, footer, theme-toggle, breadcrumb, profile-cards, mermaid
data/marketing.toml the only hand-written prose
data/generated/ written by generate-site-data, committed, checked
tailwind.css theme.js diagrams.js
static/ images copied from assets/; app.css and js/ written at build
public/ output
Zola 0.23 běží na Tera 2: komponenty nahrazují makra, import už neexistuje, indexování polí je x[1], nedefinované proměnné jsou chyby, filter a slice zmizely ve prospěch list comprehensions a slicingu ve stylu Pythonu.
Tailwind, Flowbite, Alpine
site/tailwind.css následuje quickstart Flowbite pro Tailwind v4: @import "tailwindcss", @import "flowbite/src/themes/default", @plugin "flowbite/plugin", @plugin "flowbite-typography", @source pro node_modules/flowbite a šablony a @custom-variant dark (&:where(.dark, .dark *)) z průvodce tmavým režimem. Všude se používají sémantické tokeny Flowbite v4 (bg-neutral-primary-soft, text-heading, border-default, rounded-base). Motiv jmenuje na prvním místě Inter; ten se nenačítá, takže zásobník záměrně spadne na systémové písmo.
JavaScript Flowbite se nenačítá. Dvě věci, k nimž web Flowbite používal, tedy mobilní sbalení navbaru (data-collapse-toggle) a jeho rozbalovací nabídky (data-dropdown-toggle), jsou site/nav.js, asi 2 KB, které base.html načítá odloženě a site-check vyžaduje právě jednou na stránku. Odstranění balíku o 134 KB snížilo na homepage objem skriptů a stylů z 338555 na 207140 bajtů. Styly Flowbite zůstávají; jsou to CSS, zkompilované do app.css.
Úvodní stránka je projekcí site/data/registry/product.json, kterou spustitelný soubor zapisuje z funkcí vrstvy, registru schopností a topologie webu. Každá kapitola, značka, počet, poskytovatel, druh a pravidlo na ní se čte z této datové sady; šablona žádné z nich nejmenuje a scripts/site-check selže u šablony, generátoru či navigačního souboru, který jmenuje trasu funkce nebo vlastní soubor poskytovatele. Druhý sloupec hero je odpověď, kterou vypíše majordomus product matrix, vykreslená jako tabulka, nikoli vyplněný text, aby se sloupce zarovnaly při každé šířce a čtečka obrazovky četla tabulku, ne obrázek tabulky. Slova kolem — nadpis, mantra, úvody sekcí a popisky tlačítek — patří marketing.toml, které nenese žádné číslo ani tvrzení o schopnosti a drží se rozpočtu šedesáti řádků.
Jediné, co člověk rozhoduje, je, které funkce jsou kapitoly a v jakém pořadí, a to rozhodnutí žije v samotných souborech funkcí (featured a weight), ne zde: funkce se stává kapitolou tím, že se za ni prohlásí. docs/PRODUCT.md je kontrakt, ADR 23 je rozhodnutí a project.product-surface-derived je pravidlo.
Route, které se přesunuly, se deklarují jednou, v nav.toml pod [[redirects]], vedle těch, které se nepřesunuly. Generátor z každé udělá alias Zoly na stránce, na kterou míří, takže stará adresa odpoví přesměrováním; přesměrování, jehož cíl generátor nevytvořil, shodí sestavení, místo aby publikovalo odkaz do prázdna. Stránka aliasu je přesměrování, ne stránka, takže ji scripts/lib/site-pages.awk vyjímá z kontraktu, kterému stránka podléhá.
Alpine.js je vendorován a používá se ke dvěma věcem: tlačítko kopírování u úryvků kódu (x-data, x-on:click, x-text) a rozbalení surové politiky na /policy/. Obojí degraduje: kód a politika jsou v HTML; bez JavaScriptu zmizí jen ovládací prvek.
Vlastní CSS: jedno pravidlo, [x-cloak]{display:none!important}, inline v base.html, vyžadované dokumentací Alpine. Inline atributy style="" jsou zakázány a scripts/site-check na nich selže.
Konzultovaná doporučení Flowbite
Vstupní bod Flowbite LLM (flowbite.com/docs/getting-started/llm/) odkazuje na llms.txt, což je index. Stránky přečtené a sledované dne 2026-09-04: getting-started/quickstart (direktivy Tailwind v4), getting-started/javascript (initFlowbite), customize/dark-mode (@custom-variant, značky a skript přepínače, reprodukované v theme.js), components/navbar, components/card, components/badge, components/footer, components/typography. Nainstalovaná verze flowbite v repozitáři je 4.0.2, což odpovídá dokumentovanému slovníku tokenů.
Jazyky
Web se píše jednou, v angličtině, a nabízí se v každém jazyce, který deklaruje site/i18n/languages.json (ADR 0218). Nikdo nepíše druhý jazyk: každá kopie je odvozena z anglického buildu.
| kus | co to je |
|---|---|
site/i18n/languages.json | zdrojový jazyk, nabízené jazyky, každý pojmenovaný v sobě samém |
site/i18n/<lang>/memory/*.jsonl | překladová paměť: jeden řádek na anglický segment, klíčovaný jeho hashem |
site/i18n/<lang>/guide.json | styl a glosář, které dostává každý překladatel daného jazyka |
site/i18n/<lang>/edition.toml | jazyk, který adresář deklaruje a kterého se english-only-check drží |
scripts/lib/site-i18n.mjs | průchod == languages z scripts/site-build: rozdělí každou stránku na segmenty, zapíše /<lang>/ |
scripts/site-translate | nese chybějící segmenty překladateli a jeho odpovědi do paměti |
scripts/lib/site-i18n-probe.mjs | následuje každý odkaz každé stránky, v každém jazyce, v Chromiu |
partials/language-switch.html, partials/language-detect.html | přepínač v liště a volba jazyka při příchodu |
Průchod. Po Zola, průchodu přístupnosti a diagramech se každá sestavená stránka rozřeže na segmenty — každý souvislý úsek inline obsahu mezi hranicemi bloků a každý atribut, s nímž se čtenář setká (title, alt, aria-label, popis) — s inline značkami nahrazenými číslovanými zástupci (<t1>…</t1> a <t2/> pro kód a obrázky). Kód, pre, SVG a cokoli označené translate="no" nikdy není segmentem. Kopie pod /<lang>/ je anglická stránka, v níž je nahrazen každý segment, který paměť zná, každý vnitřní odkaz míří na kopii v tomto jazyce, lang, kanonická URL a alternativy hreflang jsou nastaveny, přepínač míří na každou kopii a je odhaleno upozornění na strojový překlad. Co paměť nezná, zůstává anglicky, počítá se v /<lang>/i18n.json a je vypsáno se stránkami, na nichž je, v target/site-i18n/missing.json. Build nevolá žádný model: je to čistá funkce anglických stránek a paměti.
Překlad. Změněný anglický segment má nový klíč, takže se jeho starý překlad nikdy neodevzdá.
scripts/site-build # lists what the memory lacks
scripts/site-translate status # how much is open
scripts/site-translate run --advisor <id> # translate through an advisor of the catalogue
scripts/site-translate export --out DIR --min-pages 2 --batch-chars 16000 # batches for subagents
scripts/site-translate import DIR/*.json # admit filled batches into the memory
Překlad se přijme jen tehdy, když nese každý zástupný znak své angličtiny právě jednou, vnořený stejně; cokoli jiného se odmítne a servíruje se angličtina.
Jazyk čtenáře. Přepínač je jazykový dropdown navbaru Flowbite: každý jazyk pojmenovaný sám sebou, lang a hreflang na každém odkazu, aria-current na tom, který se čte. Čtenář, který přijde zvenčí na anglickou stránku, nic nezvolil a jeho prohlížeč preferuje deklarovaný jazyk, je odeslán na kopii stránky v něm; volba provedená přepínačem se uloží a zachová. Odkaz sledovaný uvnitř webu, opětovné načtení a crawler, který žádnou takovou preferenci neuvádí, se nikdy nepřesměrují, takže každá URL znamená stránku, kterou pojmenovává.
Autorské stránky. Stránka psaná v jiném jazyce ([extra] lang, deklarovaném v english-only-allow.txt) se do každé kopie přenáší beze změny. Její kopie ji jmenují kanonickou a dvojice autorských protějšků ([extra] alternate) si ponechává vlastní alternates.
Každý odkaz, každý jazyk. scripts/lib/site-i18n-probe.mjs načte každou stránku každé kopie v Chromiu, obsluhovanou ze samotného buildu, a drží každou u jejího jazyka: každý odkaz míří na sestavený soubor, odkaz uvnitř kopie zůstává v jazyce té kopie, přepínač vede ke každé kopii a označuje aktuální a alternativy se jmenují navzájem oběma směry.
Přidání jazyka. Jedna položka v languages.json, guide.json, edition.toml, jeho deklarace v scripts/ci/english-only-allow.txt a běh překladu. Žádná šablona, generátor ani stránka se nemění.
Lišta ostatních povrchů. /ui nosí lištu webu (scripts/ui navbar) a její přepínač jazyka vede na úvodní stránku webu v každém jazyce, dokud se UI samo nenabídne v nich (záměr one-bar-and-one-language-on-every-surface).
Trasy
Každá dlaždice na domovské stránce je odkaz na stránku s vlastním titulkem, popisem, kanonickým URL a metadaty Open Graph. Třídy tras a jejich zdroje:
| route | zdroj | šablona |
|---|---|---|
/ | site/data/registry/product.json a product-graph.json (kapitoly, rozhraní, matice, poskytovatelé, druhy, doktrína), marketing.toml (slova), readme.json (smlouva dokončení), distribution.json (instalační příkaz), sekce why | index.html |
/why/, /why/<slug>/ | site/content-src/why/*.md | why-section.html, why.html |
/features/, /features/<id>/, /features/matrix/ | site/data/registry/product.json a product-graph.json, s prózou každé stránky čtenou z vlastního souboru funkce | features-section.html, feature.html, features-matrix.html |
/getting-started/ | project.json, policy.json, lifecycle.json | getting-started.html |
/supervises/, /supervises/<slug>/ | readme.json (řádky What it does, propojené klíčovými slovy s příkazy a tvrzeními) | supervises-section.html, responsibility.html |
/commands/, /commands/<name>/ | commands.json (sekce každého příkazu v docs/CLI.md) | commands-section.html, command.html |
/profiles/, /profiles/<slug>/ | profiles.json | profiles.html, profile.html |
/policy/ | policy.json včetně surového souboru | policy.html |
/guarantees/, /guarantees/<status>/, /guarantees/<id>/ | capabilities.json, docs/claims/<id>.md | guarantees.html, status.html, claim.html |
/limitations/, /roadmap/ | readme.json sekce podle nadpisu | readme-section.html |
/architecture/ | site/content-src/architecture.md, source.json, diagrams.json | architecture.html |
/docs/, /docs/<doc>/ | docs/*.md uvedeno v docs/README.md | docs-section.html, docs-page.html |
/docs/api/, /docs/api/<tag>/, /docs/api/shared/, /openapi.json | openapi.json (z docs/generated/openapi.json) | api.html (index), api-tag.html (stránka na tag a sdílené typy) |
/docs/cli/, /docs/cli/<command path>/ | cli.json (z docs/generated/cli.json, samo je deklarací clap a cli::EXAMPLES) | docs-cli.html, docs-cli-group.html, docs-cli-command.html |
/doctrines/, /doctrines/<slug>/ | doctrines.json | doctrines-section.html, doctrine.html |
/use-cases/, /use-cases/<id>/, /applications/, /applications/<id>/ | catalogue.json | use-cases-section.html, use-case.html, applications-section.html, application.html |
/plan/, /plan/dag/, /plan/<id>/ | plan.json | plan-section.html, dag.html, milestone.html, issue.html |
/evidence/, /map/ | claims-graph.json, architecture.json | evidence.html, map.html |
/registry/ | site/data/registry/registry.json, executable.json | registry.html |
/registry/executable/ | apps/majordomus-cli/README.md, executable.json (tvrzení) | registry-executable.html |
/registry/modules/, /registry/modules/<id>/ | moduly datové sady, executable.json | registry-modules.html, registry-module.html |
/registry/capabilities/, /registry/capabilities/<slug>/ | deskriptory, měření výkonu a pokrytí datové sady, executable.json (modul, kotva API, zdroj, tvrzení, testy) | registry-capabilities.html, registry-capability.html |
/registry/cli/ | cli datové sady (deklarace clap) | registry-cli.html |
/registry/mcp/ | mcp datové sady (nástroje, zdroje, protokol) | registry-mcp.html |
/registry/benchmarks/ | benchmarks datové sady (cíle, pokrytí, politika, základní hodnoty) | registry-benchmarks.html |
/registry/artifacts/ | artifacts.json (vlastní manifest generátoru) | registry-artifacts.html |
/rustdoc/ a každá stránka, kterou pod ním rustdoc zapisuje | target/web/rustdoc/, zapsáno scripts/rust-check --doc a složeno scripts/site-build z docs/generated/web.json | — (vlastní stránky rustdoc; index.html je úvodní stránka producenta) |
/build.json | scripts/site-build | — (servírováno surově) |
/render-test/ | site/content-src/render-test.md, noindex | docs-page.html |
Slug routy schopnosti je její id s . a _ nahrazenými - (objects.search → /registry/capabilities/objects-search/, repository.scope_classify → /registry/capabilities/repository-scope-classify/): Zola takto slugifikuje každou cestu, takže datová sada pojmenovává routu, kterou Zola skutečně obsluhuje. Kotvy operací v referenci API jsou HTML id, kterých se Zola nedotkne, takže nahrazují jen . (#op-objects-search, #op-repository-scope_classify); executable.json nese obě podoby (slug, api_anchor), takže na sebe obě odkazují bez tabulky.
Trasa nativního příkazu je jeho cesta pod /docs/cli/, jeden segment na slovo, s koncovým lomítkem: ["majordomus", "bench", "baseline", "update"] je /docs/cli/bench/baseline/update/. Pravidlo je jedna funkce ve spustitelném souboru (cli::route), jí vytvořená trasa je neseno v docs/generated/cli.json a každý spotřebitel dále po proudu — generátor webu, šablony, site-check, site-probe — čte toto pole, místo aby odvozoval vlastní. Příkaz, který má pod sebou příkazy, je sekce Zola, aby jeho potomci měli trasy pod ním, a příkaz, který žádné nemá, je stránka; o čem je rozhodnuto, plyne z dat, takže příkaz, kterému naroste podpříkaz, změní tvar sám. site-check porovnává deklarované a sestavené trasy jako množiny, oběma směry: příkaz bez stránky selže a stránka, jejíž příkaz spustitelný soubor už nemá, selže jako sirotek.
/docs/cli/ patří nativní příkazové řádce, té spustitelného souboru v Rustu. docs/CLI.md specifikuje shellový nástroj bin/majordomus — jiný program, jehož strukturovaná reference je /commands/ — a vykresluje se na /docs/cli-specification/. Pravidlo, které z dokumentu dělá routu, je jedna funkce v generátoru webu (doc_slug) a routa, kterou vytvořilo, je zaznamenána v docs.json, takže přepisování odkazů, stránky a site-check ji čtou, místo aby každý počítal slug. Nepopisujte share/commands.yaml ani docs/CLI.md jako zdroje pro spustitelný soubor v Rustu: patří shellovému nástroji a oba povrchy příkazů jsou záměrně dokumentovány odděleně.
Navigace je site/data/nav.toml: hrstka záměrů (Proč, Začínáme, Koncepty, Plán, Důvěra, Spustitelný soubor, Reference), vykreslená jako rozbalovací nabídky Flowbite na desktopu a jako označené ploché seznamy ve sbaleném menu na telefonech. Drží redakční záměr — na které pevné stránky záměr vede — a nikdy výčet: moduly a schopnosti vypisuje generátor a scripts/site-check odmítne trasu modulu nebo schopnosti do ní napsanou. scripts/site-check ověřuje, že se rozřeší každý odkaz navigace a domovské stránky, že každá třída dlaždic má svou stránku, u sekce spustitelného souboru že každý modul a schopnost datové sady má stránku a žádná stránka neexistuje bez záznamu, a u příkazové řádky že trasy pod /docs/cli/ jsou přesně příkazy, které spustitelný soubor deklaruje, že každá stránka vykresluje vlastní použití, argumenty a kotvy příkladů a odkazuje nahoru i dolů, a že žádná trasa příkazu není ručně napsána do šablony, generátoru ani navigace. scripts/site-probe pak stáhne každou deklarovanou trasu příkazu z běžícího serveru a přečte zpět nejhlubší stránku příkazu.
Strategie responzivity
Mobile-first: základní třídy popisují rozložení pro telefon, sm:/md:/lg:/xl: přidávají sloupce. Každá <pre> a <table> sedí v rolovacím kontejneru, buď explicitním obalu overflow-x-auto, nebo kontejneru Typography nesoucím [&_pre]:overflow-x-auto a [&_table]:overflow-x-auto. Prvky mřížky, které drží kód, nesou min-w-0. Validace se měří, ne odhaduje: scripts/site-probe sestaví kopii pod prefixem nasazení, lokálně ji poskytne, načte každou routu v headless Chrome v iframech 320, 390 a 1280 px a asertuje document.scrollWidth == clientWidth, pak vyzkouší mobilní menu, navigační dropdown a přepínač tématu a spočítá vykreslené diagramy Mermaid. Běží v Pages workflow a přeskočí se s oznámením tam, kde není Chrome. test/cases/09_site_mobile_first.sh lintuje sestavený HTML na strukturální příčiny přetečení bez prohlížeče.
Přístupnost
Jedno h1 na stránku, <main>, <nav aria-label>, odkaz pro přeskočení, aria-current na aktivní navigaci, aria-expanded/aria-controls na přepínači menu, aria-label na ovládacích prvcích jen s ikonou, role="note" na upozorněních, viditelné fokusové rámečky (focus:ring-*, nikdy neodstraněné), kontrastní tokeny Flowbite v obou tématech. Vše kromě tlačítka kopírování a rozbalovacího prvku funguje bez JavaScriptu.
nasazení na GitHub Pages
Web publikuje .github/workflows/pages.yml, který se spouští přímo pushem na master, jehož cesty mohou web změnit, a běží vedle validate.yml, ne po něm. Jeho job deploy dokazuje, že commitnuté site/data/generated je pro strom aktuální, porovnáním kanonického hashe vstupů stromu s tím, který nese source.json (scripts/generate-site-data --fingerprint), vykreslí ho (scripts/pages build), spustí nad výstupem každou statickou kontrolu (scripts/pages check) a pushne gh-pages. Strom, jehož commitnutá odvozená data jsou zastaralá, se odmítne, ne přegeneruje.
Rustdoc reference crate je součástí těchto bajtů a není commitnuta, takže ji vyrábí vlastní úloha rustdoc, kterou deploy úloha potřebuje, ze stejného commitu přes composite action .github/actions/rustdoc — tutéž, kterou používá i validační workflow — a předává ji jako artefakt běhu. Deploy úloha ten strom stáhne před vykreslením, scripts/site-build ho složí na /rustdoc z docs/generated/web.json a scripts/site-check odmítne složenou plochu, která chybí nebo byla postavena z jiného commitu (sekce 13m). Jakmile web obsluhuje nasazený commit, scripts/pages verify-rustdoc proti němu zkontroluje veřejnou referenci a tento krok je tvrdý: nasazení, jehož veřejná reference chybí, je rozbitá nebo zastaralá, běh shodí. RUSTDOC.md má celou cestu a ADR 86 rozhodnutí.
Vše, co rozhoduje, zda se změna smí mergovat — behaviorální sada, kontroly crate, pokrytí, sada pro macOS, kontrola měření výkonu a sonda v prohlížeči — běží nad týmž commitem v validate.yml a řídí stav ci. Publikační cesta nese jen to, co může zkazit publikované bajty, a nic jiného; zdůvodnění, rozpočty a měření jsou GITHUB_PAGES_PERFORMANCE.md a CI.md má tvar validace. Úloha rust spouští majordomus generate --check a úloha site spouští scripts/generate-site-data --check; lokálně scripts/derive-check (just derive-check) spouští obě a scripts/derive (just derive) znovu vygeneruje každý odvozený artefakt v pořadí závislostí.
GitHub Pages obsluhují větev gh-pages (zdroj: větev, cesta /) a kdo tuto větev pushne, nasazuje. Dělá to jeden skript, scripts/site-deploy: odmítne špinavý strom a commit, který origin/master neobsahuje, spustí kontrolu (generate-site-data --check, majordomus generate --check, site-build, site-check, --probe na požádání), zkopíruje site/public do worktree větve gh-pages pomocí .nojekyll, commitne to se zdrojovým commitem ve zprávě a pushne. Vlastní „pages build and deployment“ GitHubu to pak obslouží za méně než minutu; patička každé stránky jmenuje commit, ze kterého byla sestavena, takže nasazení lze ověřit pomocí curl. Nezměněný výstup se nepushuje dvakrát a --dry-run ukáže commit, který by pushnul. test/cases/96_site_deploy.sh projde celou cestu proti lokálnímu bare remote: každé odmítnutí, první nasazení, opakované nasazení bez efektu a kontrolu, že site/public byl sestaven z HEAD.
Úloha .github/workflows/pages.yml je kontrolovaná forma téhož příkazu: sestaví a zkontroluje commit a pak spustí scripts/site-deploy --skip-build. Člověk spouští scripts/site-deploy (nebo just site-deploy), když operátor chce web živý bez čekání na frontu Actions, a právě tato cesta — bez jakékoli fronty před sebou — je důvodem, proč se ponechává zdroj z větve místo nativního toku artefaktů Pages, který by z běhu workflow udělal jediný způsob publikace. Postup je .ai/repo/skills/deploy-site/SKILL.md. Nasměrování Pages na větev je jednorázové scripts/site-deploy --configure-pages.
Dokumentace, kterou nasazení publikuje
Build zapisuje /docs/index.json jako poslední, s scripts/lib/docs-index.mjs. Čte stránky, které build právě vytvořil, včetně těch ze složených povrchů (reference crate na /rustdoc), takže neuvádí žádnou vlastní trasu. Každá stránka má svou trasu, titulek a popis; stránka entity je také spojena se svým objektem a index nese identitu /build.json buildu. Build selže, když trasa, kterou site/data/publication.toml publikuje, nebo stránka entity nebyla sestavena. Poté, co web servíruje pushnutý commit, workflow spustí scripts/pages verify-docs --commit <sha>. Veřejný index musí pojmenovat tento commit a každá z následujících musí odpovědět 200: kořen dokumentace, každá trasa, na které katalog publikuje druh, jedna stránka každého druhu entity, /openapi.json a /build.json. Stejný příkaz spusťte ručně proti libovolnému nasazenému commitu. test/cases/500_docs_index.sh drží generátor a sondu u jejich odmítnutí proti servírované fixture.
UI, které deploy publikuje
Web nese majordomus ui v /ui/ jako snímek čtený na publikovaném commitu (ADR 0141, docs/MAJORDOMUS_UI.md). Úloha ui-snapshot workflow sestaví spustitelný soubor z toho commitu a spustí majordomus web report ui-snapshot; běží vedle úlohy rustdoc a nasazovací úloha čeká na obě. Po scripts/pages check a před pushem nasazovací úloha položí snímek na mount, který deklaruje její vlastní surface.json. Odmítne snímek, který chybí, snímek čtený na jiném commitu a mount, který web sám už sestavil.
Cockpit se publikuje stejným způsobem na /cockpit/ (ADR 0147). Stejná úloha běží majordomus web report cockpit-snapshot po úloze UI, protože snímek Cockpitu nejdřív přečte, na co odkazuje UI, a pak tyto odkazy vede na vlastní stránky; oba adresáře se nahrají jednou, až tento krok skončí. Úloha nasazení umístí každý snímek, který model deklaruje, do přípojného bodu, jejž určuje topologie, a po pushi se scripts/pages verify-ui --surface cockpit zeptá veřejného webu, zda ho má.
Snapshot je generovaný povrch, známý jen tam, kde běžel jeho producent, takže není v commitnuté topologii a scripts/site-build jej neskládá: lokální build webu nemá /ui/, pokud se ten krok neopakuje ručně. Kontroly webu jeho stránky neposuzují.
To, že publikace to drží, je deklarováno jednou v .ai/repo/ci/pages.yaml pod deploy.snapshots: servírovaný povrch, jehož je snímkem, kam ho producent zapisuje, producent a atribut, kterým jeho stránky uvádějí svůj commit. Mount je mount povrchu v topologii a scripts/pages snapshots vypíše rozřešené řádky. Tři čtenáři podřizují publikaci tomuto záznamu (project.the-published-ui-is-the-trunks):
scripts/site-deployodmítne web, jehož strom nemá snímek na připojení, ten čtený na jiném commitu nežHEAD, nebo ten, který deklaruje jiné připojení, a řekne, jak ho umístit. Nasazení z terminálu tedy nemůže publikovat web bez/ui/.--release-metadatamění dva soubory toho, co se už servíruje, a nežádá se.scripts/pages verify-uise ptá veřejného webu, jakmile servíruje nasazený commit:/ui/surface.jsontento commit jmenuje, banner úvodní stránky jej uvádí,/ui/snapshot.jsonjej zaznamenává a říká, co čtení ukončilo, a každá stránka, kterou záznam vypisuje, odpovídá 200. Vypíše, na kolik stránek se ptal, kolik jich--max-pagesnechal bez dotazu, kolik jich snapshot sám vynechal a co jej zastavilo. Exit 10 je UI, které chybí, patří jinému commitu nebo není celé; 12 je web, který nikdy neodpověděl. Krokthe UI it publishesnasazení jej spouští a nenícontinue-on-error.- Kontrola
pages-livepokládá stejnou sondu publikovanému commitu (sekce 2cscripts/ci/pages-check), takže živé/ui/je drženo k trunku v rámci okna, v němž je web.
test/cases/2983_the_published_ui_is_the_trunks.sh drží všechny tři proti servírované fixture.
Release, který web nabízí
Které vydání je nejnovější, je jeden fakt se třemi veřejnými povrchy: domovská stránka (odznak v navigaci, hero a data-release pásu důvěry), /releases/latest.json, které řeší instalátor, a nejnovější vydání na GitHubu. Vydání je dosáhne v tomto pořadí — GitHub, pak latest.json z publikační úlohy vydání (scripts/site-deploy --release-metadata, ADR 0131), pak stránky ze sestavení masteru, o které tato úloha žádá — a záznam, který je archivuje, přistane ještě později vlastním pull requestem.
Stránky tedy záznam nečtou. scripts/site-build odvozuje release, který web nabízí, jako novější z projekce záznamu (site/data/registry/distribution.json) a releases/latest.json, které origin/gh-pages poskytuje, čtené z gitu a jmenované v build.json (release.source, release.published_from); base.html z něj nastaví offered a každá stránka čte offered. Když je novější publikovaný release, build poskytne jeho dva dokumenty, takže metadata vedle stránek jmenují to, co nabízejí. scripts/site-build --release vypíše samotné odvození.
Kontroluje se třikrát: scripts/site-check (sekce 17b) odmítne sestavení, jehož domovská stránka, /build.json a /releases/latest.json se rozcházejí, nebo jehož dvě commitnuté projekce posledního release se rozcházejí; krok the release it offers nasazení spustí scripts/pages release-live, jakmile web obsluhuje nový commit; a scripts/ci/pages-check klade stejnou sondu jako sekce 5 pages-live, podle plánu a na finish. Rozpor mladší než deploy.release_window (.ai/repo/ci/pages.yaml) po release na GitHubu je probíhající publikace; starší, nebo web nabízející verzi, kterou GitHub nepublikoval, je selhání. Pravidlo je project.the-site-offers-the-release-it-published.
Kdy se nasazení nekoná
Zveřejnění jsou dva kroky ve vlastnictví dvou stran a kterýkoli může chybět, zatímco vše viditelné zůstává zelené. Tento repozitář pushuje gh-pages; vlastní „pages build and deployment“ GitHubu mění tu větev v servírovaný web a má vlastní stav, který může být errored pro větev, jež byla pushnuta dokonale — stalo se tak 2026-09-10 v 17:35 a web 27 minut servíroval předchozí commit, aniž bylo kdekoli něco červené.
Ani vlastní závěr workflow na otázku neodpovídá. pages.yml řadí své běhy za sebe a nikdy neruší ten, který právě běží (cancel-in-progress: false; jeho zrušení vyhladovělo publikaci 2026-09-12, kdy byl každý nahrazující běh sám nahrazen), ale GitHub zahodí starší čekající (pending) běh ve prospěch novějšího a zrušený běh není selhání: 2026-09-09/10, kdy push ještě rušil běžící běh, čtrnáct ze sedmnácti zrušených běhů stihlo před zánikem pushnout gh-pages a žádný čtenář je nedokázal rozlišit od tří, které to nestihly. Běh proto říká, který to byl — anotací a řádkem v souhrnu — a samotné zrušení web uvíznout nenechá, protože čekající běh se zahazuje jen ve prospěch novějšího běhu téhož workflow a běžící běh vždy doběhne: řetěz končí během, který publikuje, nebo takovým, který zčervená.
To, co zastaralé je, je běh, který nikdy nepublikoval a jehož nástupce se pak nepodařilo sestavit. Nic v nasazení to nemůže ohlásit, protože tou dobou žádné nasazení není. Čtečkou je kontrola pages-live (scripts/ci/pages-check), která běží při každé plné validaci a ptá se na čtyři věci: publikovaný commit je na masteru, master se za něj nepohnul o víc než okno nasazení (30 minut, dimenzované podle 25minutové fronty Actions pozorované 2026-09-10), živý web obsluhuje to, co gh-pages publikovalo, a vlastní sestavení té větve na GitHubu neskončilo chybou. Samostatná sekce se ptá na pátou věc: reference na /rustdoc/ je celá a byla sestavena z commitu, který web obsluhuje, týmž scripts/pages verify-rustdoc, jaké nasazení spouští. Další se ptá totéž na snímek UI na /ui/, přes scripts/pages verify-ui. Cesty spouštěčů, jimiž rozhoduje, zda publikace je dlužna, jsou scripts/pages paths — týž seznam, který je vlastním paths: workflow — takže commit, který nemůže změnit web, nedluží nasazení.
Web odpovídá na vlastní doméně a jeden soubor ho tam drží. site/static/CNAME jmenuje hostitele; build ho zkopíruje do site/public jako každý jiný statický soubor a scripts/site-deploy ho publikuje s ostatními. GitHub Pages čte tento soubor při každém nasazení a vlastní doménu zruší v okamžiku, kdy publikovaný strom přestane soubor nést — což by s webem shodilo i inzerovaný instalační příkaz, a proto scripts/site-check odmítne build, jehož CNAME a base_url se rozcházejí. To jsou dvě místa, kde je hostitel zapsán, a třetí neexistuje: base_url je to, proti čemu se řeší každý generovaný odkaz a každá kontrola, CNAME je to, co čte GitHub. Adresa projektu, na které byl web dříve publikován, pod korczis.github.io, sem přesměrovává.
Záruka synchronizace
scripts/derive-check je jediná kontrola jen pro čtení; skládá vlastní kontroly generátorů a jmenuje každý zastaralý artefakt, než skončí:
majordomus generate --checkznovu odvodí každou projekci registru, schémat, politiky a indexu a porovná bajt po bajtu:docs/generated/**,share/allow/**, bootstrapy poskytovatelů,site/data/registry/registry.json.scripts/generate-site-data --checkregeneruje do dočasného adresáře a porovnává diffem každý generovaný soubor,docs/SITE_CLAIMS.mdadocs/PLAN_STATUS.mds commitnutými;source.jsonse porovnává podle hashe vstupu, který pokrývá každý kanonický soubor, jejž generátor čte, mezi nimidocs/generated/registry.jsonadocs/generated/openapi.json, takže změna kódu spustitelného souboru pohne hashem webu.
Řetěz se testuje hranu po hraně. apps/majordomus-cli/tests/projections.rs dokazuje, že deskriptor změněný v kódu pohne dokumentem OpenAPI, referencí, manifestem a datasetem webu, a jen sekcemi, které jej promítají (odebrané vystavení pohne trasami a pokrytím, ne nástroji; popis pohne deskriptorem všude), a že nástroje datasetu jsou nástroji povrchu MCP a jeho trasy trasami dokumentu. test/cases/95_executable_reference.sh dokazuje, že schopnost přidaná do manifestu získá svou trasu, položky indexu a odkazy samotným generátorem webu, že odebraná je ztratí bez osiřelého zbytku, a že manifest jmenující neznámý modul, chybějící zdrojový soubor nebo jiné schéma se odmítne. scripts/site-check dokazuje vykreslenou stranu: každý modul a schopnost datasetu má svou stránku, žádná stránka neexistuje bez své položky, stránky CLI, MCP a měření výkonu vykreslují každý příkaz, nástroj, cíl a základnu, každá stránka schopnosti odkazuje na svůj modul a svou operaci a žádná šablona, generátor ani navigační soubor nejmenuje schopnost ručně. test/cases/11_site_derivation.sh změní verzi, profil, princip, hodnotu politiky, tvrzení a nadpis dokumentu v pracovní kopii a ověří, že se každá změna objeví v odvozených datech; test/cases/10_site_data.sh dokazuje, že chybějící cesta nebo netestované zaručené tvrzení generátor shodí; test/cases/51_derived_artifacts_committed.sh dokazuje, že commitnuté odvozené soubory odpovídají svým zdrojům a že žádný nevkládá commit, do něhož přistává.
Commit, ze kterého byla stránka sestavena, není věcí odvozeného souboru: scripts/site-build zapisuje site/data/build.json (pro patičku, stránku architektury a „pozorováno v“ v plánu rozvoje) a site/static/build.json, servírovaný na /build.json, s commitem, časem tohoto commitu (commit_time, nikdy hodinami buildu), údajem, zda byl strom špinavý, hashem vstupu webu, otisky registru a indexu a pod surfaces každým složeným povrchem s commitem, který deklaroval jeho producent; scripts/site-check dokazuje, že servírovaný soubor jmenuje HEAD a data, z nichž byl web sestaven, a že každý složený povrch byl sestaven ze stejného commitu, takže nasazení lze zvenčí ověřit proti commitu, který se měl nasadit.
Lokální vývoj
npm ci # Tailwind, Flowbite, Alpine, Mermaid — pinned
brew install zola # or the release binary; CI pins 0.23.4
just derive # every committed derived artifact, in order (scripts/derive)
just derive-check # is every committed derived artifact current? writes nothing
just test # the gates CI would run for this working tree (scripts/ci/run-plan)
scripts/site-serve # generate, build, serve the built pages at http://127.0.0.1:1111/
scripts/rust-check --doc # the crate's reference, target/web/rustdoc — site-build composes it and refuses without it
scripts/site-build # production build into site/public/
scripts/site-check # the static checks CI runs
scripts/site-probe # the browser-measured checks (needs Chrome; --quick for one page per section)
SITE_PROBE_JOBS=4 scripts/site-probe # as CI runs it: four routes at a time
Jediný postup po změně čehokoli kanonického — deklarace v Rustu, dokumentu, tvrzení, sémantiky příkazu — je: just derive, zkontrolovat diff odvozených souborů (je to ta změna viděná ze všech projekcí), just derive-check, commitnout obojí. Zapomenutí prvního kroku zachytí třetí a také CI.
Přidání nových kanonických dat
Přidejte pole do souboru, který jej vlastní, přečtěte ho v scripts/generate-site-data, vykreslete v šabloně a rozšiřte test/cases/11_site_derivation.sh o dvojici změna-a-tvrzení. Commitněte regenerovaný site/data/generated/. Nepřidávejte pole do JSON ručně.
Přidávání nových komponent webu
Definujte komponentu Tera 2 v site/templates/components.html s využitím značek Flowbite ze stránky dokumentace komponenty, nejdřív s mobilními třídami. Volejte ji jako {{ <name attr="…" /> }}. Pokud potřebuje třídu, kterou Tailwind v šablonách nevidí, sem nepatří.
Co se nikdy nesmí upravovat ručně
docs/generated/**, share/allow/**, site/data/registry/**, site/data/generated/**, site/content/{docs,profiles,guarantees,supervises,commands,doctrines,use-cases,applications,plan,why,registry}/**, site/content/render-test.md, docs/SITE_CLAIMS.md, docs/PLAN_STATUS.md, site/static/app.css, site/static/js/**, site/static/images/**, site/static/openapi.json, site/static/build.json, site/data/build.json, site/public/**, CLAUDE.md, AGENTS.md. Změňte kanonický soubor; just derive; přestavte.