Otevřít, prohlédnout a zavřít jednu epizodu provádění. Relace je sedmý trvalý záznam a jediný, který nemá tvar úlohy.
Úloha je jednotka práce: má rozsah, má profil a může přežít pracovníka, který ji dělá. Relace je jedno sezení jednoho pracovníka: nenárokuje žádné cesty, nekontroluje přijetí a může překročit několik úloh — zatímco jednu úlohu může překročit několik relací. Ani jedno neobsahuje druhé, proto jsou to dva záznamy, a ne jedno pole.
Relace jsou volitelné. Worker, který žádnou neotevře, přijde o hranici epizody a o nic jiného; každý další záznam se zapisuje přesně jako dřív.
start [--owner <who>] [--worker <id>] [--if-open refuse|keep]otevře epizodu. Jedna otevřená relace na worktree: druhéstartse odmítne místo nahrazení první, pokud--if-open keepneříká, že se má ponechat to, co je otevřené — což je to, co předává hook poskytovatele, protože jeho událost start se spustí znovu při obnovení i při kompakci.--workerje volný řetězec identity, zaznamenaný, jen když je zadán — nezaznamenaný pracovník zůstane nezaznamenaný, protože uhodnutý je ve chvíli zápisu k nerozeznání od zaznamenaného.--providera--provider-sessionzaznamenávají, událost kterého poskytovatele epizodu otevřela, a vlastní identitu relace tohoto poskytovatele; může je dodat jen něco, co běží uvnitř hooku onoho poskytovatele, a právě to činíopened_by: hookv pracovním kontextu faktem, ne tvrzením.statusvypíše otevřenou relaci se štítkem divergence commitu, na němž se otevřela, nebo oznámí, že žádná není. Pouze pro čtení. Nepřítomnost je odpověď, ne selhání.close [--outcome closed|interrupted] [--if-none refuse|ignore]uzavře epizodu do neměnného záznamu v sekci relací vrstvy a odstraní otevřený. Na stdin může přijít autorské shrnutí a je volitelné; identifikační pole v něm se odmítají, stejně jako v checkpointu.--if-none ignoredělá z „nic nebylo otevřeno“ běžný případ místo selhání, což je to, co předává koncová událost providera.context [<session-id>]vypíše cestu k pracovnímu kontextu epizody. Pouze čtení a vypisuje cestu, ne dokument: dokument je lokální důkaz a příkaz, který ho vylije do terminálu, zve ho do něčího kontextu.
Otevření zmrazí kontext, který dostalo. start zapíše .ai/local/session-contexts/<stamp>--<session-id>.md — úvodní část epizody, výstup tvůrce kontextu doslova a sekci ## Notes pro pracovníka — a close připojí sekci ## Close jmenující výsledek a záznam. Do dokumentu se jen připisuje a nikdy se nepřepisuje, takže to, co do něj pracovník napsal, přežije. Úložiště je lokální: jmenuje tento stroj a je snímkem projekce, takže se nikdy nepublikuje ani samo nenačítá do kontextu a doctor odmítne dokument, který nese konverzaci. Hooky, které činí hranici nezávislou na tom, zda si ji někdo pamatuje vést, viz capture session.
Uzavřený záznam je obálka odkazů. Jmenuje úlohy, úkoly, milníky, checkpointy, předávky, rozhodnutí, otázky a důkazy epizody a nekopíruje tělo žádného z nich. Nese také commity mezi otevíracím a uzavíracím commitem — nebo jediný záznam diverged, když otevírací commit už není předkem, protože seznam spočítaný napříč historií, která už nesouvisí, je fikce.
Seznamy se odvozují při uzavření, nehromadí se, dokud je relace otevřená. Žádný jiný příkaz neví, že relace existují: checkpoint, decision, question a plan zůstávají beze změny. Odkazy se čtou z ledgeru, který už je jen pro připojování, už ho zapisuje jen Majordomus a už je validován.
Výběr se dělá podle razítka relace na každém řádku ledgeru, ne podle časového rozsahu. Každý řádek nese relaci, která jej zapsala, vedle commitu a větve, které už nesl. Časový rozsah byl implementován jako první a při prvním spuštění se ukázal jako chybný: ledger je jeden soubor na repozitář, dva workeři do něj zapisovali a žádné časové razítko je neodlišuje, takže obálka jedné epizody si nárokovala úlohy, checkpointy a předávky té druhé. Řádek bez relace nepatří žádné epizodě — relace jsou volitelné a práce mimo ni se nepřipisuje nikomu, místo aby se připsala tomu, kdo měl poblíž otevřenou relaci.
--outcome přijímá closed nebo interrupted. Obojí je sdělováno samotným autorem a nic se neověřuje; interrupted existuje, protože „tato epizoda byla přerušena a její záznamy mohou být neúplné“ je jediná věc o skončené relaci, která mění, co kdo udělá dál.
Kód 12 bez otevřené relace, 10 když souhrn nese pole identity, 15 když otevřený záznam patří jinému checkoutu.
list [--all]vypíše uzavřené epizody, nejnovější první, s označením odchylky u každé.show <session-id>vypíše jeden záznam celý.latest [--path]vypíše nejnovější záznam, který se rozřeší pro tento worktree a větev.
Všechny tři jsou jen pro čtení a všechny tři vypisují štítek divergence záznamu — exact, advanced, diverged, different_context. Nevymýšlí se druhý slovník pro zastaralost, protože relace napsaná před přepsáním větve a předaná dalšímu pracovníkovi, jako by stále popisovala tuto historii, je přesně to, čemu mají těch čtyři slova zabránit.
Řešení je pravidlo, které sledují všechny ostatní záznamy: stejný repozitář, stejný worktree a větev, pak stejná větev, pak nic. Záznam z nepříbuzného worktree se nikdy nenabízí — vypůjčený kontext nelze poznat jako chybný, dokud se podle něj nejednalo. --all pravidlo výslovně uvolní a ukáže větev každého záznamu, protože záznam odjinud stojí za zobrazení, když jste žádali o všechno, a nikdy za tiché podání.
Řadí se podle zaznamenaného časového razítka, přičemž pozice v knize rozhoduje o shodě uvnitř jedné sekundy. Čas úpravy souboru se nikdy nečte: nepřežije klon a není to čas, který záznam tvrdí, takže dotyk starého záznamu z něj neudělá nejnovější. Pořadí názvů souborů se obvykle shoduje s pořadím knihy, díky čemuž implementace, která sklouzla k názvu souboru, vypadá správně; test/cases/62_session_divergence.sh je záměrně rozejde a selže, když o pořadí nerozhoduje kniha.
Poškozený záznam se přeskočí s varováním na stderr, nikdy mlčky a nikdy fatálně: jeden nečitelný soubor nesmí stát celý výpis.
Jedna epizoda na relaci poskytovatele, ne jedna na worktree. Dvě okna téhož poskytovatele otevřená na jednom checkoutu jsou dva pracovníci. Jejich sloučení do jednoho záznamu označilo řádky knihy jednoho pracovníka id druhého a nechalo koncovou událost kteréhokoli okna zavřít epizodu pro oba; změřeno v tomto repozitáři 2026-09-09, sedm souběžných relací mezi sebou vyprodukovalo jeden záznam. Otevřená epizoda je proto vlastní soubor, state/sessions-open/<provider session>.yaml, klíčovaný relací poskytovatele, která ji otevřela. --if-open keep ponechává vaši epizodu — proto existuje: startovní událost se spouští znovu při obnovení a při kompakci — a jiné relaci poskytovatele dává vlastní epizodu. close --provider-session <id> zavře tuto epizodu a žádnou jinou, což je to, co předává koncová událost poskytovatele. Epizoda, kterou nikdo nepojmenoval, je klíčována hand a je nejvýše jedna: poskytovatel, který neposílá identitu relace, je nerozlišitelný od člověka u terminálu a vymýšlet tam rozdíl by množilo epizody, které nikdo nezavře. Ručně otevřená epizoda nepotřebuje nikde žádného poskytovatele a chová se přesně jako dřív.
state/session-current.yaml je relativní symlink do toho úložiště: ukazatel na epizodu tohoto checkoutu, zaměřený na tu, která byla otevřena zde naposledy, a znovu zaměřený uzavřením na tu, která zůstala otevřená, je-li právě jedna. Kterým epizodám patří příkazy daného procesu, se rozhoduje v mj_session_here_file (lib/common.sh): relace poskytovatele uvedená na příkazové řádce, jinak relace poskytovatele, ve které tento proces běží, je-li zde otevřena epizoda s takovým klíčem (MAJORDOMUS_PROVIDER_SESSION, nebo proměnná, kterou deklaruje adaptér životního cyklu — CLAUDE_CODE_SESSION_ID pro Claude Code), jinak ukazatel. Dvě otevřené epizody a proces, který nemůže jmenovat ani jednu, je jediný případ, který nelze vyřešit: ukazatel jmenuje naposledy otevřenou a session status vypíše ostatní pod Also open:, místo aby nechal hádání projít jako skutečnost.
Zapisuje: state/sessions-open/<provider session>.yaml, režim 0600, zapsáno atomicky, ukazatel vedle něj a jeden řádek session.started v knize. session_id, repository_id, worktree, branch, start_head a start_working_tree se počítají z gitu a nikdy se nepíší. provider a provider_session se zaznamenávají jen tehdy, když je dodal hook providera, což je také to, co je činí hlásitelnými: continuity.state deklaroval OpenSession.provider na rok, který žádný zapisovatel nemohl vytvořit.
Nic pod .ai/local/state/ není sledováno, včetně záznamů otevřených relací: otevřená relace nenese nic, co by kdokoli jiný potřeboval, a záznam, který by dorazil z jiného checkoutu, by tomuto dal zdědit epizodu, kterou neotevřel. Záznam, který jmenuje jiný worktree, se hlásí a nikdy se neuposlechne, což drží obranu na místě pro každý způsob, jímž může stále dorazit — zkopírovaný pracovní adresář, synchronizovaná složka.
Exit 15, když je vaše vlastní relace zde už otevřena, 10, když se záznam neparsuje — poškozený záznam selže nahlas, místo aby se četl jako „žádná relace“, protože čtení jako nepřítomného by druhému start umožnilo přepsat ho.
$ majordomus session status
No open session in this worktree.
next: majordomus session start
$ majordomus session start --worker some-provider/some-model
session s-20260904153733-fc51 opened at 2026-09-04T15:37:33Z (head 9c13909)
next: majordomus plan next; majordomus context; majordomus session close when the episode ends
$ majordomus session start
majordomus: session s-20260904153733-fc51 is open here since 2026-09-04T15:37:33Z; run majordomus session close first
$ majordomus session close <<'EOF'
The extraction boundary and the session schema landed; the compiler's discovery stage is next.
EOF
.ai/repo/sessions/20260904T171402Z--s-20260904153733-fc51--master--3c9ba2f--c0ffee1234567890.md