KADAI unter der Haube
Die Grundidee: Ein Desktop, der aus einer Beschreibung entsteht - nicht installiert, sondern instanziiert. Grundlage ist ein persönlicher Kernel: eine kleine, verschlüsselte, versionierte Selbstbeschreibung, die an beliebigen Orten instanziiert und fortgeführt werden kann - auf jedem Rechner, in jeder VM, notfalls im Browser. Jede Instanz kompiliert daraus denselben Desktop, compile(me.md, Umgebung) → Desktop, und was sie lernt, fließt in den Kernel zurück: ein System, das der Person folgt statt der Maschine.
Diese Seite erklärt, wie: das Datenmodell, die Schlüsselarchitektur, die vier Protokolle, die Steuerung über git als Control-Plane - und das Threat-Model mit seinen heutigen Lücken. Alles hier Beschriebene läuft, sofern nicht ausdrücklich als Design markiert (validiert August 2026, Plasma 6.6 / Ubuntu 26.04).
1 · Datenmodell: der Kernel
Eine Markdown-Datei (me.md) mit YAML-Frontmatter. Sechs Sektionen mit explizitem Vertrauensgefälle: identity und facts (verbindlich) · values (verbindlich, entscheidet Abwägungen, wo keine Regel greift) · preferences (weich) · rules (unverletzlich ohne ausdrückliche Zustimmung - je Aktion für alles, was die Maschine verlässt oder nicht rückgängig zu machen ist) · episodic (aktuell, möglicherweise veraltet). Jeder Eintrag trägt eine stabile ID ({#r-001}) und eine Provenienz-Zeile - wann, von wem (Mensch, Modell, Maschine). Das Frontmatter reserviert eine DID (did:kadai:…, bislang ohne externe Registry). Sektionen sind als MCP-Ressourcen (me://rules …) adressierbar gedacht - der eine Engpass, an dem Regeln durchgesetzt und Zugriffe protokolliert werden.
Das Invariant: Der Kernel speichert Bedeutung, nie Konfiguration. „Vormittags fokussiert, minimale Ablenkung" - nicht „Panel unten, Widget X". Plattform-Backends übersetzen; deshalb ist derselbe Kernel auf Plasma, in einer VM oder in einem Chat-Client brauchbar.
Instruktion und Daten (7.9.2026): Der Kernel ist, was die Person gesagt hat. Der minimale Instruktionssatz ist der der Gründungsseite - sechs Aussagen, drei erkannte Werte, der Rest abgeleitet. Beobachtete Daten (Geräte, Konten, aktueller Arbeitskontext) sind keine Instruktion: Sie können neu erhoben werden, liegen in einem eigenen Speicher (maschinen-lokal oder bei der Engine) und werden über me:// referenziert. Valide heißt schemakonform und an das Register verschlüsselt; aktuell heißt last-updated je Sektion plus regenerierbare Daten. Offen: ob facts dann weiter „verbindlich" heißt.
2 · Schlüsselarchitektur
| Material | Typ | Entsteht | Liegt | Zweck |
|---|---|---|---|---|
| Master-Identität | age X25519 | einmal, bei der Gründung (Browser oder vertraute Maschine) | nur passphrase-verschlüsselt (scrypt) als master-key.age im Repo; Klartext nie persistent | Wurzel der Autorisierung: entschlüsselt den Kernel, nimmt neue Geräte auf |
| Passphrase | menschliches Geheimnis | bei der Gründung gewählt | ausschließlich im Kopf; wird bei Eingabe direkt an scrypt verfüttert | Wächter der Master-Identität - bewusst austauschbar (später FIDO2/Biometrie) |
| Maschinen-Identität | age, je Gerät: Secure Enclave (Mac), TPM 2.0 (Linux), sonst X25519-Datei | beim Beitritt, im Sicherheitschip des Geräts, wo es einen hat | privat: im Chip, nicht auslesbar; ohne Chip als Datei (~/.config/kadai/age.key, 0600), und das Gerät sagt es; öffentlich: im Register | Alltagsentschlüsselung ohne Passphrase; auf dem Mac mit Touch ID je Öffnung |
| Sync-Schlüssel | ssh, je Gerät: im TPM (ecdsa) oder als ed25519-Datei | beim Beitritt, lokal | privat im Chip oder auf dem Gerät; öffentlich als Deploy-Key beim Repo-Host, mit Schreibrecht | Transport-Autorisierung zum Repo, ohne Präsenzpflicht, damit der stündliche Push unbeaufsichtigt läuft - orthogonal zur Inhalts-Verschlüsselung |
| Schlüsselbund | KeePass-Datenbank + age-versiegeltes Passwort | auf der ersten Maschine, aus dem Saatgut der Gründung | keyring.kdbx im Repo; sein Passwort in keyring.pass.age, verschlüsselt an das Register | Zugänge, die das System selbst braucht (Ablage, Anbieter-Token); jede Maschine öffnet ihn über ein Skript, nie als Datei |
| Tresor | KeePass-Datenbank | von der Person angelegt | vault.kdbx im Repo; Passwort nur im Kopf der Person | die eigenen Passwörter; kein Werkzeug und kein Modell öffnet ihn |
3 · Die vier Protokolle
Gründung (einmal pro Person - im Browser, komplett clientseitig)
- Deterministischer Dialog erfragt Name, Präferenzen, Passphrase, Repo-Ziel; Sprache, OS und Zeitzone werden erkannt statt erfragt; die Zeitzone legt der Dialog einmal zur Bestätigung vor.
- Im Browser: Master-Identität erzeugen (age-js) →
master-key.age(scrypt via Passphrase) → Kernel aus Vorlage generieren (inkl. Default-Regeln r-001…r-003) → an Master verschlüsseln → Register mit Master-Pubkey. - Publikation: GitLab-API (Token) oder ein kopierbares Bundle-Skript (armored age-Dateien als Heredocs,
git init && push) für jeden git-Host. Eingegebene Zugänge (Ablage, Anbieter-Token) werden an die Master-Identität verschlüsselt und als Saatgut des Schlüsselbunds mitgegeben. Geheimnisse werden nach Gebrauch aus dem Speicher gelöscht; nichts davon verlässt den Browser unverschlüsselt.
Beitritt / Enrollment (einmal pro Gerät - Selbst-Autorisierung)
- Zwei Formen: das Startabbild für eine leere Maschine, oder ein Paket mit Assistent für ein laufendes Ubuntu (
start/). Das Paket kennt den Ort des Repos, trägt die Master-Identität wie im Repo und ein an sie verschlüsseltes Token, das Deploy-Keys eintragen darf. - Passphrase-Eingabe → Master-Identität wird nur im RAM entsperrt. Gerät erzeugt Maschinen- und Sync-Schlüssel im Sicherheitschip (sonst als Datei) und trägt den Sync-Schlüssel über das Token selbst als Deploy-Key ein. Ohne Token zeigt es den Schlüssel zum Eintragen von Hand - der eine menschliche Trust-Schritt.
git clone→ Kernel mit der Master-Identität entschlüsselt → Gerät hängt seinen Pubkey ans Register → verschlüsselt Kernel und Schlüsselbund-Passwort an die erweiterte Empfängermenge neu → committet + pusht („enroll") → Probe: öffnet den Kernel mit dem eigenen Schlüssel.- Ab jetzt Alltagsbetrieb ohne Passphrase; Klartext-Master, Token und Passphrase werden verworfen. Bewiesen am 2.10.2026 auf einem alten Notebook, von der Adresse im Browser bis zum Desktop.
Jeder Boot (Steady State)
- systemd-User-Instanz startet beim Boot (Linger):
git pullals Merge, nie Rebase →age -dmit Maschinenschlüssel →me.md; OrdnungBefore=plasma-workspace.targetgarantiert: Kernel vor Shell. Danach ein Push, damit der Stand dieser Maschine hinausgeht. - Grafische Sitzung startet (im Seed: Autologin + sofortige Sperre); Begrüßung meldet Namen + Kernel-Commit-Zeit und, falls welche warten, Vorschläge aus einem Merge oder einen noch nicht zusammengeführten Tresor.
- Reconciler: liest Ist-Zustand der Shell (DBus), diff't gegen
desktop-spec.jsonaus dem Repo, wendet nur die Differenz an. Idempotent - zweiter Lauf: null Operationen.
Sync (fortlaufend)
- Alle 10 min: lokaler Commit, ohne Netz und ohne Schlüssel. SHA-256-Wächter über
me.md- nur bei echter Änderung wird neu verschlüsselt (age ist nicht deterministisch; ohne Wächter gäbe es Phantom-Commits). Geänderte Mechanik, Schlüsselbund und Tresor werden mit committet. - Push bei Anmeldung, Abmeldung und stündlich, über den Sync-Schlüssel ohne Präsenzpflicht. Wird er abgelehnt, weil eine andere Maschine zuerst da war: Merge, dann noch ein Versuch. Je Datei ein eigener Merge-Treiber (Kernel je Eintrag, Register als Vereinigung, Schlüsselbund je Eintrag durch KeePassXC, Tresor: eigener Stand bleibt, fremder wird daneben gelegt). Die git-Historie ist zugleich das Audit-Log (welches Gerät wusste wann was).
4 · Steuerung: git als Control-Plane
Es gibt keinen Steuer-Port und keine Fernsteuerungs-Session. Wer das System ändern will - Mensch oder Agent, von jedem Gerät - ändert Deklarationen im Repo: den Kernel (Bedeutung) oder die Desktop-Spec (abgeleitetes Soll). Jede Maschine reconciled sich beim nächsten Pull selbst. Eingehende Konnektivität ist ausschließlich Debug-Werkzeug. Das ist dieselbe Bewegung wie GitOps, nur dass die „Infrastruktur" hier eine Person samt ihrer Arbeitsumgebung ist - und der Diff-and-Apply-Schritt nötig bleibt, weil Plasmas eigener Layout-Load additiv ist (validierter Befund, nicht Annahme).
5 · Vorschläge: Rolle statt festem Modell, Regeln als Policy
Wer Vorschläge macht, ist eine Rolle, und die Richtung ist seit dem 24.9.2026 umgekehrt: Subsidiarität. Zwei Leitern, Fähigkeit und Ort (0 ohne Modell, 1 auf diesem Gerät, 2 in deinem Netz, 3 bei einem Anbieter). Der Router beginnt auf der kleinsten Stufe, die für diese Aufgabenklasse bisher ausgereicht hat, prüft das Ergebnis mit deterministischen Kriterien und steigt nur bei gemessenem Scheitern eine Stufe auf, höchstens zweimal. Was der Mensch annimmt oder verwirft, landet in einem Anhängelog je Maschine und bestimmt die Startstufe (bleiben ab vier von fünf Annahmen, überspringen unter einem Drittel). Der deterministische Boden bleibt: alle Mechanik (Sync, Beitritt, Reconciler, Ablage, Schlüsselbund) ist skriptbasiert und läuft ohne jedes Modell. Vor Stufe 3 zeigt der Router, was die Maschine verlassen würde, in Bytes und mit Empfänger, und wartet auf ein Ja je Aktion; rules aus dem Kernel und eine Obergrenze im Modellregister binden jede Stufe. Im Labor: 0,8-Milliarden-Modell auf dem Gerät, 2-Milliarden-Modell im Netz, ein Anbieter hinter Zustimmung; Eingang über KRunner, Ausgabe als Karten in einer Schiene am rechten Bildschirmrand, nie als Chat (kadai-subsidiarity.md, poc/rung/).
6 · Threat-Model - was hält, was (noch) nicht
| Angriff / Verlust | Stand |
|---|---|
| Repo-Host kompromittiert | liest nur Ciphertext (Kernel) + Klartext-Mechanik/Spec + Metadaten (Commit-Zeiten, Größen, Gerätenamen in Kommentaren). Kann Historie manipulieren - Commits sind nicht signiert (Lücke, s. u.). |
| Gerät verloren/gestohlen | Widerruf: Registerzeile streichen, neu verschlüsseln, Deploy-Key beim Host löschen. Aber: alte Ciphertexte der Historie bleiben für den alten Schlüssel lesbar (kein Re-Key der Vergangenheit) und der Klartext-Kernel liegt auf dem Gerät - ohne Festplattenverschlüsselung real exponiert. |
| Passphrase-Bruteforce offline | möglich für jeden mit Repo-Kopie; scrypt verteuert, ersetzt aber keine starke Passphrase. Der Wächter ist als austauschbar entworfen (FIDO2/Biometrie statt Passphrase - Design). |
| Böswilliger Kernel-Push | wer Schreibzugang + Registerplatz hat, ist eine autorisierte Maschine - by design. Schutzlinie ist das Register + Transport-Tor, nicht der Inhalt. |
| Lücke: unsignierte Commits | Enrollment- und Sync-Commits sind nicht kryptografisch ans Gerät gebunden; Gerätesignaturen (ssh-Signing mit dem Deploy-Key) wären der natürliche nächste Schritt. |
| Weitgehend gelöst (26.9.2026): Schlüssel auf Platte | Maschinen- und Sync-Schlüssel liegen im Sicherheitschip, wo das Gerät einen hat (Secure Enclave auf dem Mac mit Touch ID, TPM 2.0 in der VM). Ein Gerät ohne nutzbaren Chip bekommt Dateischlüssel und sagt es beim Beitritt. Seed weiterhin ohne LUKS; ein Umstieg von Datei auf Chip ohne Aus- und Wiedereintritt fehlt noch. |
| Lücke: der Schlüsselbund ist so sicher wie das schwächste Gerät | jede Maschine im Register kann keyring.pass.age öffnen, also auch eine mit Dateischlüssel. Deshalb enthält der Schlüsselbund nur, was das System selbst braucht, und die eigenen Passwörter liegen im Tresor, den nur die Person öffnet. Eine ausgetretene Maschine hat die Systemzugänge gesehen: Widerruf heißt auch, sie bei den Diensten zu ändern. |
| Lücke: das Beitritts-Token | das Paket trägt ein Token, das Deploy-Keys eintragen darf, verschlüsselt an die Master-Identität. Auf GitLab.com reicht so ein Token über das Konto, auf dem eigenen Forgejo über das Konto des Repos. Enger wäre ein eigenes Konto nur für den Kernel oder, als nächster Schritt, ssh-Zertifikate, die die Personenidentität signiert: dann gibt es kein Token mehr. |
| Lücke: keine Forward Secrecy | statische age-Empfänger; ein später kompromittierter Maschinenschlüssel öffnet alle Ciphertexte, die je an ihn gingen. Mitigation heute: Historie neu aufsetzen bei Schlüsselverlust. |
| Lücke: Frühe Historie | das Laborsystem trägt Klartext-Beispieldaten in alten Commits; produktive Systeme starten mit frischer Historie (Gründungsseite tut das bereits). |
| Gelöst (23.9.2026): gleichzeitige Änderungen | zwei aktive Maschinen, die denselben Kernel ändern: git kann das Chiffrat me.md.age nicht zusammenführen, also übergibt es die Datei per Merge-Treiber an .kadai-merge.py. Der führt je Eintrag zusammen: eine Seite geändert gewinnt, beide gleich ist egal, beide verschieden behält die eigene Fassung und schreibt einen Vorschlag mit allen drei Fassungen nach ~/.config/kadai/proposals/. Kein Zeitstempel entscheidet, nichts wird still überschrieben, das Repo bleibt nie im halben Merge. Basis ist die lokale Klartextkopie .me.md.base vom letzten Abgleich; .kadai-recipients nutzt gits eingebauten union-Treiber, weil die Liste ein Oder ist. Noch offen: Beobachtungsdaten als Anhängelog je Maschine, Vereinigung statt Merge; abgeleiteter Zustand (Spec, Activities) wird je Maschine neu berechnet, nie gemergt. |
7 · Status
Validiert (Stand 3.10.2026): Gründung im Browser · Beitritt per Startabbild (VM) und per Paket mit Assistent (altes Notebook, 2.10.) · drei Maschinen im Register, gleichzeitig aktiv, Merge je Eintrag · Schlüssel in Secure Enclave und TPM, getrennter Sync-Schlüssel · verschlüsselter Sync (lokal alle 10 min, Push bei An-/Abmeldung und stündlich) mit Audit-Historie · Schlüsselbund und Tresor als KeePass-Dateien im Repo · Boot-Ordnung Kernel-vor-Shell · idempotenter Reconciler · Storage-Tier (Nextcloud, protokolliert/umkehrbar) · Seed-Images arm64 und x86_64 · subsidiärer Router mit zwei lokalen Modellen und einem Anbieter hinter Zustimmung, KRunner-Eingang, Schiene (Labormaschine) · Repo auf eigenem Forgejo. Design: MCP-Modul-Laufzeit mit Manifest/Sandbox · Modell und Schiene auf jeder Maschine · Personenidentität auf FIDO-Stick, dann Telefon · Commit-Signaturen · VHDX-Pipeline · Beobachtungsdaten als synchronisierte Schicht · Tresor auf dem Telefon · Umstieg Datei → Chip ohne Neueintritt.