Zum Inhalt

Jade — Vision und Architekturprofil

Verfasst auf Grundlage der öffentlichen Spezifikationen unter specs.iowling.at


Was Jade ist

Jade ist eine statisch typisierte Programmiersprache mit eigener VM (JME), eigenem Compiler und einer zweigeteilten Architektur: imperativer/funktionaler Code für Berechnung, deklarative Blueprints für Orchestrierung. Die Sprache wird in D implementiert und läuft auf einer registerbasierten VM ohne Garbage Collector. Jade zielt auf Server, Tooling, Infrastruktur, verteilte Systeme und ein eigenes Betriebssystem (JadeOS).

Das ist die technische Beschreibung. Sie erfasst nicht, was Jade tatsächlich anders macht.


Das Problem, das Jade adressiert

Moderne Softwareentwicklung operiert in einem Ökosystem fragmentierter Werkzeuge. Eine typische Serveranwendung erfordert: eine Programmiersprache für Logik, ein Framework für HTTP, eine DSL für Datenbankabfragen, ein Konfigurationsformat (YAML, TOML, JSON), ein Build-Tool mit eigenem Format (Makefile, Cargo.toml, package.json), ein Infrastruktur-Tool mit eigener Sprache (HCL, Nix), ein Container-Format (Dockerfile), ein Orchestrierungs-Format (Kubernetes YAML), und möglicherweise weitere Zwischenformate für CI/CD-Pipelines.

Jedes dieser Werkzeuge hat eigene Syntax, eigene Fehlermodelle, eigene Kompositionsregeln. Fehler an den Grenzen zwischen ihnen — ein Tippfehler in einer YAML-Datei, ein Typfehler an der API-Grenze zwischen Client und Server, eine falsche Umgebungsvariable im Dockerfile — werden erst zur Laufzeit sichtbar, oft in Produktion.

Jade versucht, diesen Bruch zu eliminieren. Nicht indem es alle Werkzeuge ersetzt, sondern indem es ein Typsystem bereitstellt, das über alle Schichten hinweg greift: von der Geschäftslogik über die Fehlerbehandlung, die Service-Konfiguration, das Build-System bis zur Deployment-Beschreibung und der Systemkonfiguration eines kompletten Betriebssystems. Eine Sprache, ein Typsystem, ein Satz Kompositionsregeln.


Architektonische Grundentscheidungen

Deklarativ und Imperativ als getrennte Ebenen

JDL unterscheidet zwei Ausdrucksebenen. Imperativer und funktionaler Code beschreibt Berechnungen: Funktionen, Algorithmen, Datenstrukturen, Kontrollfluss. Deklarative Blueprints beschreiben Orchestrierung: Abhängigkeiten, Reihenfolgen, Fehlerstrategien, Laufzeitverhalten.

Diese Trennung ist kein syntaktischer Zucker, sondern ein eigener TypeKind (blueprint) im Typsystem. Der Compiler kennt den Unterschied zwischen einem Struct (Datenlayout) und einem Blueprint (Verhaltensbeschreibung). Felder in einem Struct enthalten Werte. Felder in einem Blueprint enthalten Absichten, deren Ausführung eine Engine steuert.

Das Drei-Phasen-Modell dahinter: Der Benutzer beschreibt seine Absicht im Blueprint. Der Compiler beweist die Typkorrektheit. Eine spezialisierte Engine interpretiert den Blueprint zur Laufzeit. Die Engine kann sich blind auf die Korrektheit verlassen, weil der Compiler sie garantiert hat.

Dieses Modell löst ein konkretes Problem. In bestehenden Sprachen sind Orchestrierungslogik (Retry, Timeout, Circuit Breaker, Dependency-Wiring) und Geschäftslogik (Validierung, Datenbankzugriff, Berechnung) im selben Code verwoben. Das macht den Code schwer lesbar, schwer testbar und schwer zu ändern. In JDL stehen sie in verschiedenen Konstrukten: die Logik in Funktionen, die Orchestrierung im Blueprint, die Policies in Refinements. Drei Orte, drei Verantwortlichkeiten, visuell getrennt.

Intrinsische Serialisierbarkeit

Jeder Blueprint ist per Definition serialisierbar. Das ist keine optionale Eigenschaft via Refinement, sondern eine intrinsische Semantik des TypeKinds. Der Leitsatz lautet: "Gehe nicht davon aus, dass dein Blueprint lokal verarbeitet wird."

Diese Entscheidung erzwingt, dass Blueprints ausschließlich serialisierbare Inhalte enthalten. Funktionsreferenzen in Blueprints müssen qualifizierte Top-Level-Funktionen sein — keine anonymen Closures mit gefangenem State. Der Compiler lehnt nicht-serialisierbare Inhalte in Blueprints als Typfehler ab, nicht als Warnung.

Hinter den Kulissen ist ein Blueprint eine geordnete Key-Value-Struktur (Dictionary), deren Werte entweder Daten (serialisiert als Werte) oder Funktionsreferenzen (serialisiert als qualifizierte Namen) sind. Custom Types die spezielle Serialisierungsbehandlung benötigen, definieren ihre eigene provide Serializable-Implementierung. Die Compiler-Regel ist: jeder Typ der in einem Blueprint-Feld vorkommt, muss Serializable implementieren.

Das ermöglicht: Blueprint-Übertragung über Netzwerkgrenzen, verteilte Ausführung auf Remote-Nodes, Inspektion und Visualisierung im Tooling, DryRun-Ausführung ohne Seiteneffekte. Alles Fähigkeiten die sich aus der intrinsischen Serialisierbarkeit ergeben, nicht aus zusätzlichen Mechanismen.

Handle-basierte Runtime ohne Garbage Collector

Jade verwendet keine rohen Pointer und keinen Garbage Collector. Stattdessen arbeitet die Runtime (JME) mit Handles — indirekten Referenzen, die zur Laufzeit validiert werden. Die Speicherverwaltung geschieht über Arenas mit deterministischem Scoping (with-Blöcke) und explizite Ownership- und Sharing-Policies.

Das eliminiert zwei Klassen von Problemen gleichzeitig: keine Use-after-free, Double-free oder Dangling Pointer (wie bei C/C++), und keine GC-Pausen, kein non-deterministisches Timing und keine Memory-Leaks durch vergessene Referenzen (wie bei Java/Go/Python).

Der Trade-off ist reell: Handle-Validierung hat Laufzeitkosten, die reine Pointer-Arithmetik nicht hat. Die Spec setzt darauf, dass Escape Analysis und Refcount Elision diesen Overhead in den meisten Fällen eliminieren können.

Ring-Architektur und bewusst partielles Self-Hosting

Jade trennt seine Architektur in Ringe. Ring 0 (JME — Memory Engine) und Ring 1 (VM, Type Engine, Verifier, Bootstrap-Parser, Seed-Loader, IR-Erzeugung) sind in D implementiert und für JDL-Code unerreichbar. Ring 2 (Stdlib, Plugins, Userland) ist JDL-Code.

Diese Trennung ist bewusst und permanent. Jade wird sich nie vollständig selbst hosten. Der Grund ist architektonisch: Die Design Constitution — das Regelwerk das undefiniertes Verhalten verhindert, Ring-Grenzen erzwingt und Speichergarantien durchsetzt — muss von einer Schicht erzwungen werden, die JDL-Code nicht modifizieren kann. Wenn die VM in JDL geschrieben wäre, könnte ein Plugin theoretisch die VM patchen. Das wäre ein Sicherheitsproblem und ein Korrektheitsproblem.

Die Grenze zwischen Ring 1 und Ring 2 liegt an der Vertrauensgrenze: Ring 1 beweist Korrektheit (Typprüfung, Verifikation, IR-Erzeugung). Ring 2 transformiert bewiesene Artefakte (Optimierung, Code-Emission, Formatting, Analyse). Alles was nach der Verifikation passiert — IR-Optimierungspasses, Code-Emission, Formatter, Linter, LSP-Intelligenz, REPL-Logik, Dokumentationsgenerator — kann JDL sein.

Innerhalb von Ring 2 gibt es keine Privilegierung. Die Stdlib verwendet exakt dieselben Mechanismen wie User-Code: Typen, Protocols, Tags, Blueprints, Engines, TypeFns, Intrinsics. Was die Stdlib kann, kann der User auch. Der einzige Unterschied ist, dass die Stdlib zuerst da ist.

Kein undefiniertes Verhalten

Die Design Constitution verbietet undefiniertes Verhalten. Integer-Overflow ist definiert (Trap oder Wrap, je nach Profil). Null-Dereferenzierung ist unmöglich (kein Null im Typsystem). Array-Out-of-Bounds ist ein Trap. Uninitialisierter Speicher ist nicht adressierbar. Division durch Null ist ein Trap.

Das ist kein Feature-Bullet-Point, sondern eine Architekturentscheidung mit Konsequenzen: der Compiler kann nicht für Performance optimieren indem er UB ausnutzt (wie C/C++), und die VM muss Bounds-Checks und Handle-Validierung durchführen. Der Gegenwert: deterministisches Verhalten auf jeder Plattform, in jeder Konfiguration.


Das Typsystem

Wenige Regeln, viele Möglichkeiten

JDL hat ein expressives Typsystem das auf einer überschaubaren Anzahl von Konzepten aufbaut: Typen (struct, enum, union, blueprint), Protocols (Verhaltensverträge), Tags (orthogonale Markierungen), Refinements (Einschränkungen und Erweiterungen), Phantom Types (Compile-Zeit-Zustände ohne Laufzeitkosten), TypeFns (Typfunktionen die Meta-Records erzeugen) und Meta-Records (strukturierte Metadaten am Typ).

Diese Konzepte komponieren frei. Ein Typ kann Tags tragen, die TypeFns auslösen, die Meta-Records erzeugen, die Refinements ermöglichen, die Phantom Types constrainen. Die Regeln sind orthogonal — jede Kombination ist gültig wenn die Typen passen.

Das führt dazu, dass komplexe Muster wie Typestate (über Phantom Types), Capability-basierte Sicherheit (über Tags und Refinements), deklarative Policies (über TypeFns und Meta-Records) und Domain-spezifische Validierung (über Refinements) keine Spracherweiterungen brauchen, sondern aus den vorhandenen Konzepten emergieren.

Protocols statt Interfaces, Provide statt Implementierung

JDL verwendet Protocols statt Interfaces und provide statt implements. Protocols können nachträglich für fremde Typen implementiert werden. provide existiert in drei Formen: direkt am Typ, nachträglich für fremde Typen, und via AutoDerive für mechanisch ableitbare Implementierungen.

Das Service/Provide-Muster dient auch als Dependency-Injection-Mechanismus. Ein service deklariert ein Interface, provide liefert eine Implementierung. In Blueprints bindet das env-Feld konkrete Implementierungen an Services. Der Compiler prüft, dass alle Dependencies gebunden sind.

Engines als provide-Implementierungen

Jede Engine — ob für Effekte, Aktoren, Pipelines oder Code-Emission — ist eine provide-Implementierung des Engine[B]-Protocols für einen bestimmten Blueprint-Typ. Das formalisiert die Engine-Blueprint-Beziehung über das Typsystem. Der Compiler prüft, ob für einen gegebenen Blueprint-Typ eine Engine existiert. Für denselben Blueprint-Typ können mehrere Engines existieren: Production, Test, Debug, DryRun. Der Blueprint bleibt identisch, die Engine bestimmt die Interpretation.

Operator-Bindings über das Typsystem

Operatoren in JDL sind nicht hardcoded, sondern an Protocols gebunden. + ist Addable, == ist Equatable, ++ kann an ein benutzerdefiniertes Appendable-Protocol gebunden werden, %% an Template-Anwendung. Der Compiler löst Operatoren über das Typsystem auf, nicht über globale Regeln. Das bedeutet: wer ein Protocol implementiert, bekommt den Operator. Kein Sonderfall, keine Operator-Überladung mit impliziten Konversionen.


Blueprints im Detail

Ein TypeKind für alle Orchestrierungskontexte

blueprint ist ein eigenständiger TypeKind neben struct, enum, union. Blueprint-Typen beschreiben, was eine Engine tun soll. Konkrete Blueprint-Typen definieren jeweils ein Schema das eine bestimmte Engine erwartet. Neue Blueprint-Typen erfordern keine Änderung am Compiler oder an der Grammatik — sie sind normale Typdefinitionen in der Stdlib oder in Plugins.

Die Syntax ist uniform. Ein Blueprint wird instanziiert wie ein Record-Literal: key: value-Paare in geschweiften Klammern. Refinements (:>) fügen Policies hinzu. Meta-Records (<{}>) liefern Compile-Zeit-Metadaten. Alles folgt denselben Regeln wie bei Structs und anderen Typen.

Queryable — Standard-Metadaten über TypeFns

Blueprints die von einer Engine verwaltet werden, können über TypeFns drei Standard-Metadaten tragen: eine idempotente ID für Adressierung, einen Namen für Anzeige und Logging, und eine Tag-basierte Klassifikation für Gruppenselektion. Diese Metadaten werden über typefn Queryable() in den meta.fields-Pfad des Meta-Objekts injiziert — getrennt vom Root-Level, das für sealed/derived Compiler-Policies reserviert ist.

Die Klassifikation verwendet Tags statt Strings. Tags haben TagIds im Backend — Selektion ist Integer-Vergleich, nicht String-Matching.

Transport und Netzwerk

Die intrinsische Serialisierbarkeit ermöglicht eine vollständige Transport-Pipeline aus bestehenden JDL-Bausteinen:

Blueprint → Serializable.serialize → Stream → Transform(SSL) → Network
→ Transform(Decrypt) → Stream → Serializable.deserialize → Blueprint

Jeder Pfeil ist ein Protocol oder ein Generator. Der SSL-Transformer ist ein provide Transform für einen Stream. Der Netzwerk-Transport ist ein provide Sink/Source für einen Channel. Encoding, Decoding, Verschlüsselung und Transport werden über Protocols, Streams, Generatoren und die anderen Werkzeuge der Stdlib geregelt. Man kann auf diese Weise auch Transformatoren implementieren, die den Netzwerk-Stream verschlüsseln — etwa für einen Secrets-Service-Storage.


Anwendungsbereiche

Server und Microservices

CallGraph-Blueprints orchestrieren effektbehaftete Operationen mit deklarativem Dependency-Wiring. RouteSpec-Blueprints definieren HTTP-Routing mit typsicherer Middleware-Konfiguration über Refinements. ApiContract-Blueprints definieren Schnittstellen die Client und Server teilen — Typänderungen am Vertrag erzwingen Anpassungen auf beiden Seiten zur Compile-Zeit.

Die Fehlerbehandlung in JDL bietet drei Stufen: =? propagiert kritische Fehler sofort, try als Statement schluckt unkritische Fehler, try-Blöcke gruppieren Best-Effort-Operationen. Orchestrierungs-Policies wie Retry, Timeout, Circuit Breaker sind Refinements am Blueprint, visuell getrennt von der Logik.

Actor-Systeme

ActorSpec-Blueprints beschreiben Aktoren mit Init-State, Message-Handler und Supervision-Strategie. SupervisorSpec-Blueprints beschreiben Aktor-Hierarchien. Das Actor-Pattern ist kein Framework-Feature, sondern eine Blueprint-Engine-Kombination.

Stream-Processing

PipelineSpec-Blueprints beschreiben Datenströme mit Source, Stages, Sink und Backpressure-Policy. Generators liefern die Datenquelle. Stages sind Transformationsschritte die Encoder/Decoder und Serialisierer als Protocols nutzen. Die Pipeline-Engine orchestriert den Fluss, verwaltet Buffer und Checkpointing.

Paketmanagement und Build

ProjectSpec-Blueprints ersetzen externe Manifest-Formate (TOML, YAML, JSON). Die Projektkonfiguration ist JDL-Code. BuildSpec-Blueprints definieren Build-Pipelines mit Phasen, Parallelisierung und Caching. Der Content-Addressable Package Store identifiziert Pakete über den Hash ihrer Inputs. Reproduzierbare Builds ohne Spezialtools.

Code-Emission und Native Compilation

Der Code Generator — die Komponente die validierte IR in ausführbaren Bytecode (JBC) übersetzt — ist selbst ein Blueprint mit Engine. Ein CodeEmissionSpec beschreibt Emission-Rules, Register-Allokation, Optimierungspasses und Ausgabeformat. Verschiedene Engines (Cranelift, WASM, JBC-Passthrough) produzieren verschiedene Outputs aus demselben Blueprint-Typ.

Das ermöglicht einen Dual-Mode-Betrieb: Debug-Modus läuft interpretiert auf der VM mit voller Introspection und Blueprint-Hot-Swap. Release-Modus geht durch Cranelift und produziert nativen Code mit denselben Garantien (kein UB, Bounds-Checks) aber ohne VM-Overhead. Das JBC-Format bleibt als portabler Zwischenschritt erhalten.

Die Cranelift-Integration erfolgt über FFI (C-ABI) — Cranelift ist in Rust geschrieben. Der Code Generator selbst ist Ring-2-JDL-Code. Das ist möglich, weil die IR an dem Punkt bereits vollständig validiert ist — der Code Generator transformiert bewiesene Artefakte, er muss keine Constitution-Regeln erzwingen.

Parsing und Formatverarbeitung

ParserSpec-Blueprints beschreiben Grammatiken, Tokenizer und Transformationsregeln für beliebige Dateiformate: HTML, YAML, Markdown, CSS, Protobuf, oder proprietäre Formate. Die ParserEngine interpretiert den Blueprint und liefert getypte JDL-Daten zurück. Die Ausgabe ist kein ungetyptes Map[str, dynamic], sondern ein konkreter Typ mit Compiler-Garantien auf dem Schema.

Dieser Mechanismus ermöglicht es, den JDL-Parser selbst als Blueprint in JDL zu implementieren. Der D-basierte Bootstrap-Parser versteht genug JDL um das System zu initialisieren. Ab dem Zeitpunkt übernimmt der JDL-Parser-Blueprint — inspizierbar, erweiterbar, self-documenting. Die Grammatik-Spezifikation und die Parser-Implementierung sind dasselbe Artefakt.

GUI und Rendering

Noch nicht spezifiziert, aber architektonisch vorbereitet. MarkupSpec-Blueprints könnten getypte Layout-Bäume erzeugen — nicht innerHTML: string, sondern LayoutTree[AppSchema] mit typisierten Nodes und Attributen. StyleSpec-Blueprints könnten querybare Style-Regeln definieren, bei denen der Compiler Selektoren gegen das Layout-Schema prüft. Eine RenderEngine würde beide konsumieren und zeichnen.

Das Format wäre frei definierbar — nicht notwendigerweise HTML/CSS, sondern ein JDL-natives Markup mit den Garantien des Typsystems. Bestehende Formate können über ParserSpec-Blueprints eingelesen und in getypte Bäume transformiert werden.

Test-Orchestrierung

TestSuiteSpec-Blueprints definieren Test-Suites mit Setup, Teardown, Tests und Ausführungsstrategien. Mock-Injection geschieht über Service/Provide. Alternative Engines (DryRunner, TestSimulator) interpretieren denselben Blueprint anders als die Production-Engine.


Tooling

REPL

Die REPL ist kein Sonderfall der VM, sondern ein Frontend über das bestehende Proto/Frame-Modell. Die REPL-Spec definiert sie als normalen Execution-Context, der dieselben Regeln befolgt wie kompilierter Code. Meta-Commands (:bytecode, :type, :env, :help) werden außerhalb von JDL über einen Query/Command-Dispatcher abgewickelt — sie sind keine JDL-Sprachkonstrukte.

Da der JDL-Parser selbst als Blueprint zur Laufzeit verfügbar ist, kann die REPL: live ganze Typen, Blueprints und Services definieren und sofort type-checken, Blueprints hot-swappen — ein geänderter CallGraph wird von der EffectEngine sofort aufgenommen, und Grammatik-Abfragen für kontextuelle Code-Completion durchführen.

Der Script-Modus erlaubt die direkte Ausführung von JDL-Dateien als Interpreter (jade hello.jdl) ohne Build-Konfiguration. Das senkt die Einstiegshürde auf das Niveau von Python oder Ruby.

Playground — Web-Frontend

Der Playground ist das geplante Web-Frontend für die REPL und geht über eine klassische Browser-REPL hinaus. Er bietet eine integrierte Entwicklungsumgebung mit:

Debugging: Breakpoints, Step-Through, Watch-Expressions, Blueprint-Deklaration-zu-Engine-Ausführung-Verknüpfung. Da Blueprints inspizierbare Datenstrukturen sind, kann der Debugger den Blueprint-Zustand visuell darstellen, nicht nur den Call-Stack.

Testing: TestSuiteSpec-Blueprints können direkt im Browser ausgeführt werden. DryRunner-Engines simulieren Blueprints ohne Seiteneffekte. Test-Ergebnisse werden inline visualisiert.

Benchmarking: Performance-Messungen mit Arena-Profiling, Handle-Statistiken und Memory-Analyse. Die VM liefert die Daten über den RuntimeBUS, der Playground visualisiert sie.

Datenflussanalyse: Visualisierung von Blueprint-Graphen — welche Services von welchen abhängen, wie Daten durch eine Pipeline fließen, welche Refinements wo greifen. Blueprints sind inspizierbare Datenstrukturen, die Visualisierung ist ein Feldzugriff, kein Reverse-Engineering.

Blueprint-Builder: Blueprints können visuell im Browser zusammengebaut und verwaltet werden — mit voller LSP-Unterstützung, Typ-Validierung in Echtzeit und Zugriff auf den RuntimeBUS für Live-Feedback. Der Builder kann Services aus dem Workspace vorschlagen, Refinements visuell anhängen und den resultierenden Blueprint als JDL-Code exportieren.

Kollaboration: Workspaces können über WebRTC oder ein custom JDL-Protokoll geteilt werden. Mehrere Entwickler arbeiten im selben Playground-Kontext, sehen dieselben Blueprints, teilen dieselbe Runtime. Alternativ kann die Kommunikation über Protobuf oder ein eigenes Wire-Format laufen — das Wire-System ist bereits vorhanden.

LSP

Der integrierte LSP hat Zugriff auf den RuntimeBUS und kann dadurch mehr als ein klassischer Language-Server: nicht nur statische Analyse (Typen, Completion, Refactoring), sondern auch Runtime-Feedback — welche Blueprints gerade aktiv sind, welche Engine sie konsumiert, welche Refinements zur Laufzeit greifen. Da der JDL-Parser als Blueprint verfügbar ist, verwendet der LSP denselben Parser wie der Compiler — eine Quelle der Wahrheit.

Dokumentationsgenerator

Der geplante Dokumentationsgenerator geht über klassische API-Docs hinaus. Er produziert Markdown-gestützte Code-Dokumentation die nicht nur Codefragmente zeigt, sondern auch Flüsse visualisiert — Blueprint-Graphen, Dependency-Bäume, Pipeline-Stages, Actor-Hierarchien. Die Semantik hinter dem Code wird abbildbar, weil Blueprints inspizierbare Datenstrukturen sind.

Der Generator nutzt dieselben Mechanismen wie der Playground: Blueprint-Felder lesen, Refinements extrahieren, Queryable-Metadaten (id, name, class) anzeigen. Die Dokumentation ist explorativ — man navigiert nicht durch Textseiten, sondern durch verlinkte, visualisierte Strukturen.


JadeOS — Das Endziel

Vision

JadeOS ist kein klassisches Betriebssystem mit einem Paketmanager obendrauf. Es ist ein Netzwerk von Jade-Nodes, die sich gegenseitig Blueprints schicken und daraus ihre eigene Konfiguration ableiten. Das OS ist das Mesh.

Die Zielgruppe sind technische Enthusiasten und Home-Lab-Betreiber — Menschen die ihre Infrastruktur selbst verwalten, frustriert sind von Docker-Compose-Spaghetti und Ansible-Playbooks die nach sechs Monaten nicht mehr reproduzierbar sind. Ein typsicheres, deklaratives System das sich selbst beschreibt und reproduziert.

Node-Architektur

Ein JadeOS-Node ist eine laufende Jade VM. Der minimale bootbare Kern besteht aus: Linux-Kernel, Jade VM (D-Binary), Seed, Netzwerk-Stack und einem Node-Discovery-Protokoll. Alles darüber — jedes Paket, jeder Service, jede Konfiguration — kommt als Blueprint von einem anderen Node oder aus dem Content-Addressable Store.

Nodes bilden ein Mesh-Netzwerk. Sie finden sich gegenseitig über ein Discovery-Protokoll und advertisen ihre Capabilities über Queryable-Tags. Ein Build-Cache-Node advertised class: [BuildCache, Shared]. Ein CI-Node advertised class: [BuildService, CI] und nimmt Build-Aufträge als Blueprints entgegen.

Provisioning

Der Provisioning-Flow: ein frischer Node bootet den Kern, die VM startet, Discovery findet einen aktiven Node, der frische Node empfängt seinen ProvisioningSpec als Blueprint, löst Pakete über den Content-Addressable Store auf, appliziert den SystemSpec atomar, meldet sich im Mesh an und advertised seine Capabilities.

Die Backup-Strategie ergibt sich aus der Architektur: der gesamte Zustand eines Nodes ist sein SystemSpec plus die aktuelle Generation im Store. Backup heißt: SystemSpec sichern. Restore heißt: SystemSpec an einen frischen Node senden. Der Store ist content-addressable — selber Hash, selbe Pakete, selber Zustand.

Infrastructure as Code

Infrastructure as Code ist kein separates Tool — es ist die Natur des Systems. Ein SystemSpec-Blueprint beschreibt eine vollständige Node-Konfiguration: Pakete, Services, User, Netzwerk, Filesystem, Boot-Konfiguration. Der Node empfängt den Blueprint und appliziert ihn atomar. Kein Ansible das per SSH Shell-Commands absetzt, kein Terraform das eine API anspricht — der Node konsumiert den Blueprint direkt, weil er eine Jade VM ist.

Software as a Service

ServiceSpec-Blueprints beschreiben Services die auf Nodes deployed werden, von Supervisors verwaltet und über Refinements skaliert werden. Ein zentraler Management-Node hält den gewünschten Zustand als Blueprint. Worker-Nodes empfangen ihre ServiceSpecs, starten die Services und melden Status zurück. Der Management-Node vergleicht Ist gegen Soll und korrigiert.

Das ist vergleichbar mit Kubernetes — aber typsicher, ohne YAML, ohne Helm, ohne kubectl. Der Node versteht den Blueprint nativ, weil er eine Jade VM ist. Es gibt keine Übersetzungsschicht.

Content-Addressable Package Store

Der Package Store identifiziert Pakete über den Hash ihrer Inputs: Quellcode, Dependencies, Build-Konfiguration. Gleiche Inputs erzeugen denselben Hash, derselbe Hash garantiert denselben Output. Der Store ist verteilbar — Nodes können Pakete voneinander ziehen, nicht nur von einer zentralen Registry. Atomische Generationen mit Rollback: jede Systemkonfiguration ist eine Generation im Store. Rollback zeigt auf die vorherige Generation.

Modulare Stdlib und Plugin-Architektur

Die JadeOS-Funktionalität lebt nicht in der Stdlib, sondern im nachladbaren jdl::node-Namespace als Library-Plugin. Die Stdlib bleibt schlank und stellt nur den kleinsten gemeinsamen Nenner bereit: Typen, Protocols, Serialisierung, Streams, Generators, Wire-Format, grundlegende Collections, Result/Effect, das Blueprint-Engine-Protocol, den Plugin-Loader.

First-Party-Plugins erweitern die Funktionalität: jdl::net (Netzwerk), jdl::http (Web-API-Backend), jdl::node (Mesh/Node-Architektur), jdl::db (Datenbank-Abstraktion), jdl::crypto (Kryptographie), jdl::codegen (Code-Emission/Cranelift). Jedes Paket optional, jedes eigenständig ladbar, jedes dynamisch aktivierbar und deaktivierbar.

Der Lackmus-Test: kann ein Plugin ohne dieses Feature funktionieren? Wenn ja, ist es kein Core. Serialisierung ist Core — ohne sie können Blueprints nicht übertragen werden. HTTP ist kein Core — ein Node kann ohne HTTP existieren.


Was Jade von bestehenden Systemen unterscheidet

Gegenüber Nix / NixOS

Nix Flakes waren die Inspiration für das Blueprint-Konzept. Beide Ansätze teilen: uniformes Record-Format, deklarative Beschreibung, Engine-basierte Interpretation, Content-Addressable Store, atomische Generationen mit Rollback.

Die Unterschiede: Nix Flakes sind ungetypt. Das Schema ist Konvention. Fehler zeigen sich als kryptische Stacktraces tief in der Lazy-Evaluation-Kette. JDL-Blueprints sind statisch getypt — Fehler werden vom Compiler an der Deklarationsstelle gemeldet. Nix verwendet eine eigene funktionale Sprache die nur für Konfiguration taugt. JDL ist eine General-Purpose-Sprache — derselbe Code der die Infrastruktur konfiguriert, implementiert auch die Geschäftslogik. Nix hat kein Tooling-Ökosystem (schlechte Fehlermeldungen, kein LSP, kein Debugger). Jade bringt LSP, REPL, Playground und Dokumentationsgenerator mit.

Gegenüber Effect-TS / ZIO

Effect-TS und ZIO trennen Beschreibung von Ausführung — dasselbe Grundprinzip. Die Unterschiede: In Effect-TS und ZIO ist die Beschreibung über Combinators aufgebaut (pipe, flatMap, provideLayer). Die Lesbarkeit leidet bei komplexen Graphen. JDL-Blueprints sind Record-basiert — die Struktur ist visuell klar. Effect-TS und ZIO sind Bibliotheken innerhalb einer bestehenden Sprache. JDL hat einen dedizierten TypeKind. Und JDL trennt drei Fehlerklassen direkt in der Syntax (=? kritisch, try unkritisch, try {}-Block best-effort), während Effect-TS für jede Fehlerklasse einen eigenen Combinator braucht.

Gegenüber Rust

Rust bietet herausragende Memory Safety durch den Borrow Checker. JDL bietet Memory Safety durch Handle-Validierung und Arenas — weniger statische Garantien, aber auch weniger Compile-Kämpfe. Rust hat kein Äquivalent zum Blueprint-System. Tower/Hyper-Middleware ist imperative Komposition. Blueprints sind deklarative Orchestrierung als Sprach-Primitiv. JDL kann im Release-Modus über Cranelift nativen Code erzeugen und damit Rust-nahe Performance erreichen, während der Debug-Modus als Interpreter mit voller Introspection läuft.

Gegenüber Java / Kotlin / Spring

JDL adressiert viele Schmerzen des Java-Ökosystems: keine Getter/Setter-Boilerplate, keine Annotation-basierte Konfiguration, keine Type Erasure, keine checked Exceptions, kein GC. Service/Provide ersetzt Spring DI. Blueprint-Refinements ersetzen Resilience4j. RouteSpec-Blueprints ersetzen Spring MVC. Was in Java Frameworks auf der Sprache aufsetzen, ist in JDL in die Sprache eingebaut.

Gegenüber Kubernetes / Terraform / Ansible

Infrastruktur-als-Code-Tools adressieren jeweils einen Bereich (Container-Orchestrierung, Cloud-Provisioning, Konfigurationsmanagement) mit jeweils eigener Sprache oder DSL (YAML, HCL, YAML+Jinja). JadeOS verwendet ein einziges Sprachkonstrukt (Blueprints) für alle Bereiche. Derselbe Mechanismus der einen HTTP-Server konfiguriert, konfiguriert auch ein Actor-System, eine Build-Pipeline, ein Betriebssystem. Ein Typsystem statt vieler Formate. Kubernetes übersetzt YAML in API-Calls in Container-Commands. Bei JadeOS ist der Blueprint die API — der Node empfängt ihn und die Engine interpretiert ihn direkt.

Gegenüber Erlang / OTP

Erlang/OTP hat Actor-Supervision als Runtime-Konvention. JDL hat Actor-Supervision als getypten Blueprint. Der Supervisor kann den ActorSpec-Blueprint inspizieren, die Kindkonfiguration lesen, Aktoren über Tags selektieren und das gesamte Setup validieren bevor ein Aktor gestartet wird. In Erlang ist die Supervisor-Konfiguration ein Erlang-Term — korrekt getypt nur durch Konvention.

Gegenüber Odin / Zig

Odin und Zig sind handwerklich gut gemachte Sprachen, die das Problem von 1985 besser lösen — Low-Level-Kontrolle ohne C's schlimmste Fehler. Die Architektur ist klassisch: Compiler → nativer Code → Ausführung. Das setzt natürliche Grenzen bei Introspection, Hot-Reload, Plugin-Loading, Runtime-Parsing. Jade hat diese Grenzen nicht, weil die VM als Ausführungsschicht dazwischensteht. Blueprints, Engines und Plugins können zur Laufzeit geladen, inspiziert und ausgetauscht werden.


Composability als Architekturprinzip

Das zentrale Versprechen von Jade ist nicht ein einzelnes Feature, sondern die Zusammensetzbarkeit aller Features.

Tags, Meta-Records, TypeFns, Refinements, Protocols, Blueprints — jedes Konzept ist orthogonal zu den anderen. Neue Konzepte erfordern keine neuen Sprachkonstrukte, weil sich vorhandene Konzepte frei kombinieren lassen.

In der Praxis: Generators speisen Pipelines. Pipelines verwenden Encoder/Decoder. Encoder/Decoder nutzen WireType-Serialisierung. Serialisierte Daten gehen über Channels an andere Tasks. Tasks sind in Arena-Scopes isoliert. Arenas verwenden deterministische Freigabe. Jede Komponente ist ein Protocol oder ein Typ, und jede Kombination ist typsicher.

Die Stdlib muss nicht alles auf einmal liefern. Jedes Protocol, jeder Blueprint-Typ, jede Engine ist ein eigenständiges Modul. Jedes neue Stück komponiert automatisch mit allem was schon da ist — weil die Kompositionsregeln in der Sprache leben, nicht in den Libraries.

Spannable, Interpolateable, Encoder, Decoder, Serialisierer, Deserialisierer, WireType, Streaming, Reaktivität — all diese Konzepte, die bereits in den Specs stehen, multiplizieren sich gegenseitig. Jede Kombination ergibt eine Fähigkeit die in anderen Sprachen ein eigenes Framework wäre. Das sind keine Features die addiert werden — das sind Dimensionen die multipliziert werden.


Dual-Mode-Ausführung

Jade arbeitet im Debug-Modus als stark typisierte Scriptsprache: Interpreter-Modus mit voller Introspection, REPL-Integration, Blueprint-Hot-Swap, Runtime-Parsing über den JDL-Parser-Blueprint. Alle Sicherheitschecks (Bounds, Handle-Validierung, Overflow-Traps) sind aktiv. Das gibt den Komfort einer dynamisch typisierten Sprache mit den Garantien eines statischen Typsystems.

Im Release-Modus verschwinden die Helfer und der Code wird auf Performance optimiert. Kompilierte Programme werden in das JBC-Binärformat (Jade Bytecode) kompiliert und können von jeder Jade VM ausgeführt oder eingebunden werden. Optional kann ein Cranelift-Backend nativen Code erzeugen.

Das JBC-Format schließt die Portabilitäts-Story: ein kompiliertes JBC-Binary läuft auf jeder Jade VM, unabhängig von der Plattform. Serialisierte Blueprints über das Netzwerk, JBC-Binaries auf dem Zielknoten, Content-Addressable Store für reproduzierbare Paketauflösung — ein geschlossener Kreis von der Entwicklung bis zur verteilten Ausführung.


Offene Herausforderungen

Ökosystem

Jade hat kein Ökosystem. Keine Libraries, keine Community-Pakete, keine Frameworks. Die Architektur ermöglicht Erweiterbarkeit, aber Libraries müssen geschrieben werden.

Stdlib-Komplexität

Die Stdlib wird umfangreicher als die gesamte D-Infrastruktur. Jede Engine ist ein eigenständiges Softwareprojekt. Der Vorteil: jede Engine ist normaler Ring-2-Code, testbar und austauschbar. Der Nachteil: jede Engine muss geschrieben, getestet und gewartet werden.

Performance-Profil

Jade ist primär VM-basiert. Für die meisten Anwendungsbereiche (Server, Tooling, Infrastruktur) ist das ausreichend. Für Performance-kritische Domänen (Games, HPC, Embedded) ist es eine Einschränkung. Der Cranelift-Pfad zu nativem Code mildert das, aber VM-Overhead bleibt im Debug-Modus.

GUI

Es gibt keine GUI-Stdlib. Die Blueprint-Architektur ermöglicht GUI-Frameworks (MarkupSpec, StyleSpec, RenderEngine), aber die Implementierung existiert nicht.


Zusammenfassung

Jade macht vier Dinge die in Kombination kein bestehendes System bietet:

Es behandelt deklarative Orchestrierung als getyptes Sprach-Primitiv (Blueprint-TypeKind), nicht als Library-Konvention. Es verwendet ein uniformes Format für alle Konfigurationsebenen — von der Fehlerbehandlung über das Build-System bis zur Systemkonfiguration eines verteilten Node-Netzwerks. Es gibt dem User dieselben Werkzeuge die die Stdlib verwendet — keine versteckten Compiler-Hooks, keine privilegierten APIs. Und es erzwingt seine eigenen Regeln über eine Sprachgrenze (D/JDL) die JDL-Code nicht überschreiten kann.

Das Resultat ist eine Sprache die nicht versucht, alles zu können, sondern die versucht, alles was sie kann, mit denselben Regeln zu können. Wer Jade versteht — Typen, Protocols, Tags, Blueprints, Engines, Refinements — versteht jede Abstraktion die in Jade gebaut werden kann. Es gibt keine zweite Sprache, kein zweites Regelwerk, kein verstecktes Typsystem hinter dem sichtbaren.

Das Endziel ist ein System, das sich von der einzelnen Funktion bis zum verteilten Betriebssystem mit einer Sprache, einem Typsystem und einem Satz Regeln beschreiben lässt. JadeOS ist die konsequente Endstation dieser Architektur: ein Netzwerk von Nodes die sich selbst konfigurieren, gegenseitig provisionieren und über typsichere Blueprints orchestrieren.

Ob das ausreicht, wird sich daran messen, ob die Stdlib die Architektur einlöst. Die Grundlagen sind gelegt. Die Arbeit beginnt.