This is the agreed target architecture for the Ziran and Kryon repositories. It is not a claim that every part is implemented. Current gaps are tracked in Implementation status.

Repository ownership

Repository Owns Must not own
Ziran Language semantics, parser, checker, laws, standard library, .zir, native backends, .zx linker, verifier, loader, and generic execution runtime Widgets, UI trees, styling, DOM policy, renderers, Kryon-specific names or implicit UI startup
Kryon Importable .zi modules for widgets, layout, themes, interaction, accessibility, rendering, and platform adapters Ziran syntax, compiler branches for widgets, or an application's terminal or product UI

The dependency direction is Kryon → Ziran. A CLI, service, or library can use Ziran without Kryon. Importing Kryon is an explicit source dependency. Kryon's maintained implementation, including its widget and runtime logic, is 100% Ziran source. A platform adapter may call operating-system or third-party APIs through declared FFI or host capabilities; those external libraries are dependencies, not a second copy of Kryon's implementation. Generated C or Go is compiler output, not Kryon source.

Language boundary

Modules, records, functions, imports, and procedure values are general language features. Calls resolve against visible function signatures and record types. Their semantics do not depend on the callee's spelling. Button, Text, and Image mean nothing until imported or declared. Kryon's intended Image(ImageProps) surface is an ordinary library API, including when used for semantic images; its full rendering implementation is still being migrated. A record argument uses Function(Props.{value = 42}); result: Result = Function(Props.{value = 42}) binds a non-void return value.

Ziran has no #ui function modifier, app/route syntax, widget fallback, #style directive, DOM fields in its IR, or renderer-specific type checks. Kryon defines its own composition, styling, navigation, and lifecycle APIs in .zi. If a general language feature is needed for those APIs, it must work for unrelated libraries too and pass the same checker and backend tests.

Language laws constrain semantics, types, evaluation order, IR validity, and backend equivalence. Kryon owns its UI behavior and rendering laws. Language direction sets the additional requirements for law-driven development, LLM tooling, parallel execution, and evolution.

Compilation and execution

.zi modules ──parse/check──> .zir modules
.zir modules ──native backend──> C or native Go output
.zir modules ──link/verify──> .zx ──portable runtime + host capabilities──> process

Inside the compiler, names in that model are interned: an expression's or statement's name and type, and a function's parameter list, are shared immutable strings (KeepName, KeepParameters), so equal spellings within a compilation context are one pointer. Parameter lists are split once into names and types (ParametersOf). Type and procedure resolution keep entry-scope answers, including misses and ambiguity, until declarations or imports change (SymbolLookupsChanged). Lookup file spellings remain part of each key; recursive import walks retain separate cycle state. make sanitize checks each kept answer against a fresh lookup.

Record bodies share immutable parsed field snapshots. Field lookup uses an index over that snapshot, and ownership checking can reuse the fact that every field is a built-in value or pointer. This shortcut never assumes facts about named types, arrays, or generic applications: those still resolve in their owning scope. Rewriting a body selects a new snapshot, so copied or relocated record declarations cannot retain stale field names or ownership facts.

Every backend consumes the same checked .zir model. Native output may bind declared platform libraries. .zx contains portable executable content and cannot depend on arbitrary target-specific C or Go source fragments. Native and portable builds of the same supported program must agree on observable language behavior.

Semantic checking sets ZirFunction.checked only from language validity. Native symbol planning runs afterward, and body eligibility is a separate emitter query. An emitter's inability to represent a valid function does not turn that function into unchecked source. The portable verifier remains the authority for executable .zx support.

Parameter declarations have one immutable parsed view, including binding names, types, namespace modifiers, and defaults. Record fields likewise use the shared field snapshots. Backends consume these views; source spellings remain available for diagnostics, template rewriting, and serialization.

Compilation contexts own interned text, source paths, symbol answers, declaration snapshots, expression caches, and reusable scratch buffers. Source and artifact readers create a context when the caller has not selected one. Programs and linked copies retain the contexts whose bytes they borrow; closing the original program therefore cannot invalidate a linked copy. Source spans keep their original context independently of the module's lookup context. Context pointers and cache identities are never serialized.

Public source parsing is a recoverable operation. Syntax and source-read errors return NULL after reporting the ordinary structured diagnostic. An operation-local allocation transaction releases partial trees, temporary buffers, and open streams after an error, and restores the enclosing parser state. Transactions nest across import callbacks and are local to each thread. Published immutable caches remain owned by their context. See Compiler embedding for lifetime and concurrency rules.

The linker resolves explicit imports, includes the reachable library code, and reports unresolved symbols or unavailable capabilities. A program with no Kryon import has no Kryon code or graphics requirement. A program importing Kryon links the Kryon modules it uses; graphics, input, audio, filesystem, and other host access must be declared as capabilities when needed. The host supplies those capabilities. A missing required capability is a reported error, never silently ignored.

The portable runtime launches a non-graphical .zx without initializing a window or display. Kryon decides how to use the host's graphical capabilities through its imported .zi implementation. The compiler and loader do not inspect widget names to make that decision.

Product boundary

Kryon is a reusable library. Applications keep their own product logic and UI in their repositories and import Kryon. Kapsule's terminal emulator, for example, belongs to Kapsule; Kryon only gains small reusable primitives when multiple applications need them. See Migration for the single breaking cutover and verification gates.