AppGenerator Output Assembly Contract¶
Status: Canonical contract Purpose: Define exactly how AppGenerator turns persistent UI intent into bundle artifacts.
Owned Artifacts¶
AppGenerator owns the deterministic product bundle artifacts for persistent app UI:
app.jsonadmin/admin_registry.yamlui/pages/*.yamlbrand/theme_config.jsonconfig/shell.jsonconfig/asset_manifest.json
The ownership split is strict:
app.jsondefines app identity, targets, auth intent, and startup behavior such asstartup.landing_spot.admin/admin_registry.yamldeclares all admin portal pages for the app's operator console. Module panels reference these page ids via thepagefield inmodules/{module}/contracts/admin.yaml.ui/pages/*.yamldefine persistent page structure and route ownership.brand/theme_config.jsondefines visual tokens, shared primitives, and semanticui.chat/ui.shell/ui.pagestyling.config/shell.jsondefines compact app-wide shell behavior: header logo/actions, canonical shortcuts, navigation policy, non-page-owned navigation items, and chrome mode defaults.config/asset_manifest.jsondefines reusable media inventory metadata for non-token assets (icons/images/video), including source/provenance and usage hints.
AppGenerator does not own agent workflows, agent UI tools, or workflow transition surfaces. Those belong to AgentGenerator and the workflow UI contracts.
When AppGenerator assembles module artifacts into the app workspace, companion manifests stay under modules/{module}/contracts/. Canonical event files are contracts/events.yaml, contracts/reactions.yaml, and contracts/notifications.yaml; do not flatten them to the module root or emit deprecated contracts/subscriptions.yaml for new output. Persistent module backends use backend/schemas.py, not backend/models.py.
Upstream Inputs¶
AppGenerator should compile these inputs in priority order:
captured_theme_config- optional canonical ThemeCapture artifact
-
strongest visual source when present
-
app_build_plan -
carries
theme_preferences,brand_intent, optionalshell_preset_hint, pages, entities, capability packs, auth, and integrations -
experience_spec_document/ui_design_document -
persistent page intent and layout guidance
-
concept_blueprintand related design docs - fallback context when no stronger artifact exists
Compilation Flow¶
1. ThemeCapture¶
ThemeCapture produces canonical visual evidence only.
It emits:
themeidentityassetsprimitivesfontscolorsshadowsui.chatui.shellui.page
It does not emit shell content such as header actions, profile menu items, notification copy, or footer links.
2. AppSchemaAgent¶
AppSchemaAgent compiles persistent UI into one AppSchemaOutput with six payloads:
manifestpagescustom_route_bundletheme_config_patchshell_configasset_manifest
Theme vs Shell Ownership¶
Two artifacts handle visual and behavioral customization:
theme_config_patch→ visual tokens only: colors, typography, spacing scale, shadows, density,ui.chat/ui.shell/ui.pagesemantic stylingshell_config→ shell behavior only: header logo/actions, canonicalshortcuts,navigation.policy, non-page-ownednavigation.items, andchromemode overrides
shell_preset_hint is not an artifact. It is prompt-time AppGenerator guidance from factory_app/workflows/AppGenerator/tools/shell_presets.yaml. AppSchemaAgent uses it to choose page navigation, page shell_mode, and whether a compact shell_config override is necessary. The preset id is never written into the generated app bundle.
Do not mix them. Raw spacing/width/density tokens belong in theme_config_patch. Header action labels and app-wide shell placement rules belong in shell_config.
Rules:
manifest.default_routeis persisted toapp.json -> startup.landing_spotcustom_route_bundleis a rare bounded escape hatch for persistent routes that cannot be expressed cleanly through shipped primitivestheme_config_patchis a partial patch forbrand/theme_config.jsonshell_configis a partial patch forconfig/shell.jsonasset_manifestis a partial patch forconfig/asset_manifest.json- raw spacing, width, density, and sizing tokens belong in
theme_config_patch, notshell_config - generated
shell_config.shortcutsmay only containheader,profile,mobile,footer, andfooterHideOnMobile - do not emit custom shortcut catalogs or shell fields outside
AppShellConfigPatch - shell actions may use semantic
variants[].whenfor context-aware label/target changes; do not emit path-prefix, wildcard, or query-param override rules - page-owned shell navigation belongs on
ui/pages/*.yaml -> navigation;shell_config.navigation.policyowns app-wide placement rules - page-owned header/footer/bottom-bar intent belongs on
ui/pages/*.yaml -> shell_mode;shell_config.chromeowns only app-wide mode-policy overrides - reusable media inventory belongs in
asset_manifest, not intheme_config_patchorshell_config - custom routes must be owned exclusively by
custom_route_bundle(ui/route_manifest.json+ui/pages/custom/*.jsx) and must not duplicate anyui/pages/*.yamlroute - every custom route manifest entry must have exactly one
page_filesentry whoseregistry_keymatches the routecomponent;save_app_schemasynthesizesui/index.jsfrom that matched pair app/ui/index.jsmust register every component referenced byui/route_manifest.json; missing registrations are export/download blockers, not runtime surprisesadmin/admin_registry.yamldeclares admin page and panel metadata; it is not a route registry and must not own full-page custom route components- hosted-pack pages must bind through an app-owned facade module endpoint such as
/api/modules/analytics_dashboard/get_metrics, never directly to hosted-pack internals - declarative pages may launch workflow sessions through typed page actions (
action_type: workflow), but workflow-local React still belongs to AgentGenerator andchat.tool_call
Hosted-pack facade binding¶
When a build has a host-provided pack, AppGenerator must keep the generated app boundary explicit:
hosted_pack
-> backend/integrations/{pack_id}_client.py
-> app-owned facade module
-> ui/pages bind to the facade module
Provider-neutral example:
hosted_analytics
-> backend/integrations/hosted_analytics_client.py
-> modules/analytics_dashboard/
-> ui/pages/analytics.yaml
-> /api/modules/analytics_dashboard/get_metrics
The pack descriptor may provide surfaces, supported_domains, branding, generation_rules, supersedes, adapter_template, and capability_source. Those fields are planning metadata. They do not authorize generated pages to call hosted service internals directly.
Route/component registration drift¶
For custom full-page React routes, the route contract is complete only when all of these are true:
ui/route_manifest.json -> pages[].componentnames the runtime component keyui/pages/custom/*.jsxcontains exactly one default-exported page for that keyui/index.jsregisters the same key throughregisterComponent- no declarative
ui/pages/*.yamlroute owns the same path - no implicit file discovery or admin-registry fallback may substitute for the three files above
Generation should catch missing or mismatched component registrations before download/export.
2b. AdminRegistryAgent¶
AdminRegistryAgent runs after AppUIQualityAgent passes and before AssemblyAgent.
It produces AdminRegistryOutput with two payloads:
admin_registry— typedAdminRegistryobject (page list with ids, labels, paths, icons, scope, order)code_files— serializedadmin/admin_registry.yaml
Rules:
- Always emits
overviewandsettingsapp-scope pages - Includes additional standard pages (
users,billing,usage,activity,operations,integrations,support) based onapp_build_plan.capability_packsentity domains andauth_strategy - Includes hosted-only pages (e.g.
hosting) only whenavailable_hosted_packsis non-empty and contains the relevant pack id — never in OSS or self-hosted contexts - Uses
scope: appfor all generated app pages; workspace-scope pages only for hosted operator contexts - Hosted global operator registries belong to hosted product workspaces and must not be emitted into standard generated app bundles
- Page ids must cover every entity domain that
ConfigMiddlewareAgentassigns module admin panels to - The module contract quality gate validates at generation time that every
admin.yamlpanelpagefield resolves to a declared page id
Hosted-only pages:
| Page id | Inclusion condition | Path |
|---|---|---|
hosting | available_hosted_packs contains hosting or deployment | /apps/:appId/hosting |
Add new hosted-only pages here when a hosted capability pack introduces a new operator surface. Do not add them to the standard inclusion rules.
AssemblyAgent must include admin/admin_registry.yaml in the final bundle output.
3. save_app_schema¶
save_app_schema is the persistence tool for schema-driven app bundles.
It must:
- write generated artifacts under
$MOZAIKS_GENERATED_ARTIFACTS_PATH/apps/{app_id}/{build_id}/app/ - write
app.json - write
ui/pages/{name}.yaml - write
ui/route_manifest.jsonwhencustom_route_bundleexists - write
ui/pages/custom/*.jsxwhencustom_route_bundleexists - synthesize
ui/index.jsfromcustom_route_bundle.page_fileswhen custom routes exist - reject or warn on custom route registry drift before assembly: missing page files, duplicate registry keys,
.jsroute files, non-default-exported React, or route components that no page file registers - deep-merge
theme_config_patchintobrand/theme_config.json - deep-merge
shell_configintoconfig/shell.json - deep-merge
asset_manifestintoconfig/asset_manifest.json - store
app_manifest,app_pages,app_custom_route_bundle,app_theme_config_patch,app_shell_config,app_asset_manifest, andapp_schema_readyin workflow context
It must not write directly into an active runtime-loaded app root such as a workspace's app/ bundle or factory_app/app. Activation requires an explicit promotion step.
4. AssemblyAgent¶
When app_schema_ready == true, AssemblyAgent must emit those artifacts back out as code_files so downstream download/export tools can bundle them.
Required schema-driven outputs:
app.jsonadmin/admin_registry.yamlui/pages/{name}.yamlui/route_manifest.jsonwhenapp_custom_route_bundleexistsui/pages/custom/*.jsxwhenapp_custom_route_bundleexistsui/index.jswhenapp_custom_route_bundleexistsbrand/theme_config.jsonwhenapp_theme_config_patchexistsconfig/shell.jsonwhenapp_shell_configexistsconfig/asset_manifest.jsonwhenapp_asset_manifestexists
When app_schema_ready == false, AssemblyAgent should use MFJ fan-in via assemble_app_tasks and must still preserve the page contract.
4b. Raw Frontend Path Removed¶
AppGenerator no longer carries a secondary raw frontend page/component generation lane.
Rules:
- ordinary persistent pages still compile through
AppSchemaAgent - raw React page/component tasks do not belong in AppGenerator build plans outside the explicit
custom_route_bundlecontract - shell content compiles through
shell_config, not through a separate frontend shell agent - if the primitive system is insufficient, the platform should add a primitive, pattern, or page capability rather than reviving a second frontend codegen path
5. IntegrationReadinessAgent¶
IntegrationReadinessAgent runs after AssemblyAgent and before validation or download. It is not a manual preflight step. It is the agentic fan-in point for third-party connector needs discovered while planning or executing decomposed build tasks.
Inputs:
app_build_plan.external_integrationscapability_packs[].required_integrationsbuild_tasks[].integration_needsmfj_app_task_resultsfrom child task fan-inintegration_needsrecorded by task agents withrecord_integration_need
Rules:
- Reuse ready app-scoped connectors from the platform connector store.
- Prompt inline only for unresolved required credentials or required non-secret connector configuration.
- Emit structured
integration.requiredrequests withintegration_id, provider/service id,purpose,required_fields,secret_fields,non_secret_fields,permissions_required, and resume context. - Persist newly supplied credentials through the platform connector service so
/apps/{appId}/integrationsreflects the result. - Persist only frontend-safe non-secret config in connector metadata. Secret fields are write-only and must not be returned to chat, generated code, or frontend read APIs.
- Do not generate app-owned API-key tables, credential collections, or custom credential forms.
- If required credentials are declined or unavailable, block validation/download and return to the user with the unresolved service list.
6. generate_and_download¶
generate_and_download is the bundling tool.
It does not reason about artifact ownership. It packages the materialized file set into the downloadable app bundle.
7. AppValidation Strategy¶
AppValidationAgent must use an explicit validation strategy contract instead of implicit E2B-only behavior.
Canonical strategy values:
e2blocalskip
Canonical status values:
passedfailedskipped
Rules:
- Studio/hosted environments may prefer
e2bwhen sandbox credentials are available. - CLI/local environments may resolve to
localor explicitskip. - generation/export must not be blocked solely because E2B is unavailable.
skipis explicit and deterministic; it is not a hidden fallback and it is not reported aspassed.- export gating must allow only
passedor explicitskipped, and still requires integration readiness and wiring checks to pass.
Materialization rule:
- typed agent outputs such as
app_backend_admin_config,python_files, andjs_filesare the source of truth for their owned lanes - the same applies to
database_files,model_files, andbackend_foundation_bundle.files - extraction may regenerate canonical file content from those typed fields before packaging
- raw
code_filesare the serialized mirror, not the authority, when a typed lane exists
Bundle Rules¶
Do:
- keep persistent pages declarative
- keep shell content separate from shell styling
- reuse ThemeCapture output when available
- deep-merge generated theme/shell patches into canonical runtime files
Do not:
- generate raw React files for persistent pages by default
- generate any AppGenerator-managed raw React page/component files for persistent pages
- place header/footer action content in
theme_config.json - place spacing/padding/density tokens in
shell.json - place reusable media inventory in
theme_config.jsonorshell.json - route visual shell concerns through AgentGenerator
Why This Exists¶
Without this split, AppGenerator either under-specifies visual/media control or mixes styling, shell behavior, and asset inventory. The contract above keeps bundle generation deterministic, keeps ThemeCapture reusable, and gives the runtime a stable set of artifacts to consume.