CLI architecture
The Morphir CLI owns command parsing, configuration use, provider registration, and user-facing output. Shared crates provide workspace discovery, extension resolution, verified activation, and protocol sessions.
Command structure
morphir
├── compile # Language-neutral compilation
├── generate # Language-neutral code generation
├── gleam # Gleam compile, generate, and roundtrip workflows
├── extension # Verified extension repository and installation management
├── ir # IR operations
└── ...
Provider registry
The CLI constructs a fresh transport-neutral provider registry, represented by ExtensionRegistry, for each operation that needs a provider. It registers the native Gleam extension as a built-in and then adds validated installed-state snapshots. Built-in registration belongs to the CLI because the executable decides which implementations it links. The daemon has no Gleam dependency.
The registry records two independent properties:
ProviderOriginisBuiltinorInstalled.InvocationModeisNativeDirect,NativeMep,ProcessMep, orWasmMep.
Resolution works in this order:
- Filter providers by the requested frontend or backend operation, language or target, and normalized Morphir IR version.
- Apply origin precedence among the eligible providers. Installed providers override built-ins.
- Apply the caller’s invocation policy to the selected provider.
PreferDirect selects NativeDirect for a native built-in. ProtocolOnly selects NativeMep, which runs the same extension instance through a MEP session. Installed process and WebAssembly providers remain MEP-only under both policies.
This ordering matters. An installed extension that lacks the requested capability or IR version cannot hide an eligible built-in.
Extension release schema "1.0" requires frontend and backend selector metadata whenever the corresponding capability is declared. The installer preserves that metadata in schema "1.0" catalog and lock records, so typed registry resolution uses only validated languages, targets, and Morphir IR versions.
Compile flow
The general compile path performs these steps:
- Discover and load the effective project configuration through
morphir-devkit. - Resolve the input and output paths.
- Read source files into sorted
SourceDocumentvalues. - Construct the CLI-owned provider registry.
- Resolve
frontend.compilefor the language and Morphir IR version withPreferDirect. - Invoke the selected native or MEP route.
- Validate diagnostics and the returned IR, then write
morphir-ir.jsonfrom the host. - Format human, JSON, or JSON Lines output.
The single-file Elm compatibility path still launches its configured process extension directly. It does not use the built-in Gleam route.
Generate flow
Generation performs these steps:
- Discover configuration and resolve the requested IR input.
- Prefer
morphir-ir.jsonwhen the input is a compile-output directory. Otherwise load the directory as a Morphir document tree. - Detect and normalize the Morphir IR version.
- Construct the CLI-owned provider registry.
- Resolve
backend.generatefor the target and IR version withPreferDirect. - Invoke the selected native or MEP route.
- Validate returned artifact paths and let the host write the files.
- Format command output.
Extensions return artifact descriptions. They do not choose arbitrary host filesystem destinations.
MEP execution
NativeMep, ProcessMep, and WasmMep share the daemon’s validated session lifecycle. The host initializes the session, checks provider identity and capabilities, invokes the operation, and shuts the session down. A failed transport preserves whether the peer stopped or entered an indeterminate state.
Installed providers reach that session only after the distribution layer verifies the selected artifact against its catalog and lock state. The registry never treats an unverified file beside the CLI executable as a built-in.
Output and errors
Human output prints the final success details and diagnostics. JSON pretty-prints one CompileOutput or GenerateOutput. JSON Lines prints that same result object compactly on one line; it does not emit progress events. The CLI maps configuration, filesystem, provider-resolution, protocol, and extension diagnostics into miette reports at the command boundary.