---
title: Module Console UI
description: Publish a receipt-bound console_ui_esm artifact for an exact Module Release.
---

A Module can ship operator UI as an immutable `console_ui_esm` artifact. The UI
belongs to the Module Release, not to the Console repository, and loads only
after Console validates the connected System receipt and every artifact binding.

## Contract shape

`ModuleManifest.console` contains `ConsoleSurface` declarations. Each source
declaration owns its `name`, `label`, `route`, `presentation`, optional `icon`,
required capabilities, and optional navigation. For executable UI,
`ConsoleSurfacePresentation::Esm { entry }` names the ESM entry. This source
shape does not carry an `area` field.

The framework derives the artifact's generated
`ConsoleModuleManifest.surfaces` list from those executable declarations. Each
generated `ConsoleModuleSurface` uses `id`, `path`, `label`, the route-derived
`ConsoleModuleSurface.area`, required capabilities, optional icon, and optional
navigation. Do not copy generated presentation fields back into
`ModuleManifest.console`.

`ModuleManifest.console_slots` and `ModuleManifest.console_contributions` are
separate extension declarations. They are not context fields inside a
`ConsoleSurface` and are not members of the generated
`ConsoleModuleSurface`.

The same Module Release carries one `ConsoleUiArtifact` with:

- format `console_ui_esm`;
- artifact locator and SHA-256 digest;
- generated `lenso.console-module.v1` presentation manifest;
- independent `hostApi` and `consoleUi` compatibility ranges;
- named ESM entries and optional style assets, each digest-bound;
- immutable provenance that agrees with the owning Module Release.

Console rejects a missing entry, mismatched digest, incompatible protocol
range, undeclared Surface, or artifact owned by a different Module Release.

## Runtime API

The entry imports `@lenso/console-module-api` for its framework-neutral manifest
and typed host operations. React Surfaces use `@lenso/console-ui` for the
adapter, Surface root, shared primitives, and typed StyleX slots. Console
injects immutable slot context; the Module UI does not import Console internals.

Use the Host API for navigation, locale, current actor, System context, and
same-origin Surface Gateway calls. Keep the Surface renderable for these four
object states:

- `connected`: normal operations are available;
- `unavailable`: show the server-provided reason and a retry affordance;
- `incompatible`: name the contract or artifact mismatch;
- `unmanaged`: explain that no Management Binding covers the object.

## Business API calls

Generate a client from the Module's committed OpenAPI contract. The Surface
calls that client through the Surface Gateway; it never constructs a Service
base URL or attaches Service credentials.

Every request is constrained by the connected app's Surface Grant:

- Console actor and optional tenant;
- Module identity and Module Release digest;
- UI artifact digest;
- Business API contract digest;
- exact allowed operation IDs.

The gateway fails closed when any binding changes. Direct browser-to-Service
traffic is outside the supported model.

## Packaging loop

1. Build the ESM bundle and generated presentation manifest.
2. Hash the JavaScript and every style asset.
3. Attach the artifact to the same immutable Module Release.
4. Run the owner-local Module Release and Console artifact checks.
5. Compose a new `lenso.app.json` revision that selects the exact release.
6. Connect that exact topology and verify the Surface in a real browser.

For operation design, continue with
[Business APIs and Console Surfaces](/docs/admin-surfaces). For System binding
and browser authority, read [Lenso Console](/docs/runtime-console).
