Workflow Routing Transitions¶
The global workflow routing layer lives in factory_app/workflows/extended_orchestration/extension_registry.json. App/workspace roots may overlay it with their own workflows/extended_orchestration/extension_registry.json.
It is not agent routing, not app navigation, and not workflow-local task batching.
Overlay Contract¶
App/product workspaces that need hosted or operator-specific workflow entries without copying the shared factory registry declare:
The OSS loader then builds one effective registry:
workflows[],entrypoints[],workflow_sequences[], andtransitions[]merge byid.{ "id": "...", "remove": true }removes an inherited item.artifact_dependency_graphmerges by family key.- App-local workflow folders override matching inherited workflow folders.
- Referenced inherited factory workflows resolve from packaged
factory_app/workflows/.
Do not copy default factory workflow registry entries into an app repo just to make hosted routes work.
Contract¶
extension_registry.json has three concerns:
| Concern | Field | Owner | Purpose |
|---|---|---|---|
| Workflow registry | workflows[] | platform/workflow author | Known workflows and hard dependencies |
| Workflow sequencing | workflow_sequences[] | runtime | Auto-advance and transition checkpoints after workflow completion |
| Transition routing | transitions[] | platform shell author | User choices, context seeds, silent redirects, confirmations |
Workflow Launch Taxonomy¶
workflows[] also declares how each workflow participates in the user-facing conversation. This is first-party Mozaiks workflow metadata, not workflow-specific product logic.
| Field | Purpose |
|---|---|
startup_mode | Workflow start category read from the workflow's orchestrator.yaml; all existing orchestrator.yaml files are supported |
interaction_mode | Whether the workflow is user_guided, agent_directed, or backend_only |
launch_behavior | Whether an empty workflow chat should auto_start, wait_for_user, or never start in chat |
handoff_style | Whether the workflow should feel like continuous_chat, a separate_chat, or background work |
startup_mode does not by itself decide whether the UI waits on a blank chat. For user-reachable workflows, the registry should normally use launch_behavior: "auto_start" so transition handoffs feel like the same conversation. UserDriven means the user participates in the workflow; it does not mean the user must type the first message after every transition.
For example, the brownfield intake path can route to the path selector first. Both the Add AI Workflows and Build App Features choices seed deterministic context such as brownfield_build_path and then continue into ExistingAppDiscovery, which uses that selected scope while it reads the app. The downstream build sequence can use the same context later when it hands off into the enhancement or generation phase.
Use this taxonomy instead of hardcoding workflow names in runtime code:
- User-facing sequence workflows usually use
interaction_mode: "user_guided"or"agent_directed",launch_behavior: "auto_start", andhandoff_style: "continuous_chat". - Standalone manual workflow starts may use
launch_behavior: "wait_for_user"andhandoff_style: "separate_chat"when a blank chat is intentional. - Domain-event workflows use
startup_mode: "BackendOnly",interaction_mode: "backend_only",launch_behavior: "none", andhandoff_style: "background".
Workflow sequencing uses workflow_sequences[]. Treat this data as workflow sequence metadata, not shell navigation or workflow-local task batching. If a sequence includes an entry transition as its first step, entrypoints[] points to that transition for actual route entry.
Workflow-local task batching lives in:
Do not put task batch graphs in the global registry.
Hard Rules¶
- For shared build transition visuals, place transition components in
factory_app/workflows/extended_orchestration/ui/and export them fromui/index.js. - Keep transition UI files focused on transition screens only; keep shared runtime helpers in
chat-ui/src/platform. - Do not put top-level
component,config, title, background, option label, or option description fields in product transition declarations. - Do not put
entry_transitionon workflow sequence declarations. - Do not put product-specific presets such as dogfood shortcuts in the global transition schema.
- Transition
context_variablesmay seed deterministic context only when the target workflow declares those keys incontext_variables.yaml. - Use
entrypoints[]entries withtransition: <id>to enter a transition screen. - Transition entry routes should use
meta.shellMode: "focused"and transition UI should useui.shell_mode: "focused"unless the transition intentionally needs normal product chrome.
Transitions¶
Transitions are router decisions. They may render UI, but the declaration stays semantic and workflow-agnostic.
{
"id": "app_type_selector",
"transition_type": "user_choice_context",
"ui": {
"component": "AppTypeSelector",
"mode": "screen",
"shell_mode": "focused"
},
"options": [
{
"id": "greenfield_app",
"route_to": "ValueEngine",
"context_variables": { "app_type": "greenfield_app" }
},
{
"id": "brownfield_app",
"route_to": "ExistingAppDiscovery",
"context_variables": { "app_type": "brownfield_app" }
}
]
}
Supported target types:
route_tocan point to another transition id.route_tocan point to a workflow id.- The loader stamps
route_typeinternally after validation. - Transition UI emits
option_id; it does not emitroute_to. - All user choice transitions declare
route_toon each option. - Use
user_choice_contextwhen the main point is deterministic context seeding, even if multiple options still route to the same next step. - Use
user_choice_routewhen the main point is branch routing across different targets. options[].context_variablesis merged into the accumulated transition context before target workflow creation.- The workflow start path filters context against the target workflow's
context_variables.yamldefinitions. - Keep transition declarations semantic. Put branded copy/images/layout in the React component file referenced by
ui.component, not in transition option routing fields.
The shell renders transition UI through TransitionScreen. ui.component is a registry key, not a file path. Built-in screens such as LauncherScreen and ConfirmScreen are available for generic cases. For product-specific visuals, create a workflow-local transition component and export it via:
The registry owns routing and context semantics (transition_type, single-route route_to, options[].route_to, and options[].context_variables).
chat_session Transition Type¶
chat_session launches a workflow in the current chat surface without mounting a blocking overlay. It is the correct type for any post-generation review or revision interaction where the user must be able to type freely in the chat.
Declaration:
Rules:
route_tois required and must point to a registered workflow id.chat_sessiontransitions must NOT declare auiblock — they never render an overlay component.confirm_route,cancel_route,options,context_key, androutesare not valid onchat_sessiontransitions.
Runtime behavior:
- The sequence auto-advances to the
chat_sessiontransition after the preceding workflow completes. TransitionScreenreceives the transition, detectschat_session, and immediately callsonResolve(null)without mounting any UI.- The shell calls
/api/transitions/resolveand receivesresolution_type: "chat_session"withchat_id,workflow_id, and the filteredcontext_variablesfrom the active journey. - The shell switches the active chat session in-place to the launched workflow — no navigation away, no overlay, no blocked input.
- The target workflow receives the accumulated journey
context_variablesfiltered against its owncontext_variables.yamldeclarations.
When to use:
Use chat_session when the interaction after transition must happen conversationally — the user can type revision requests, the agent can respond, and the flow can conclude through agent-authored completion signals rather than a button-driven confirm/cancel overlay.
The canonical example is app_review, which launches the AppReview workflow so the ReviewAgent can present a build summary artifact in chat and the user can type revision requests or click Promote without a blocking screen. Revision events emitted from this chat session must carry the reviewed artifact_key, artifact_version_id, source_surface=app_review, lifecycle_state, and staged bundle_path so the Refinement Engine routes against the reviewed bundle rather than an ambient app workspace. If the trigger response is harness_decision, the chat shell must feed it into the shared pending harness decision UI before launching any downstream workflow.
Dependencies¶
Dependencies are hard prerequisites and belong on workflow entries:
SessionRouter enforces these before workflow start. Dependencies are not cards, tabs, or transition options by default.
Workflow Sequences¶
workflow_sequences[] is the preferred field for ordered workflow auto-advance:
{
"id": "build",
"description": "Full build pipeline.",
"affected_declarative_families": ["concept", "brand", "design_docs", "workflow_bundle", "app_bundle"],
"steps": [
{ "transition": "app_type_selector" },
{ "workflows": ["ValueEngine"] },
{ "transition": "coding_journey_selector" },
{ "workflows": ["DesignDocs"] },
{ "workflows": ["AgentGenerator"] },
{ "workflows": ["AppGenerator"] }
]
}
Rules:
- Use sequences only when completion of one phase should automatically start the next phase.
- Use one workflow per step for serial execution.
- Use multiple workflows in one step only when they should run as a parallel phase.
- Use
{ "transition": "<id>" }when a completed workflow should pause on a surfaced checkpoint before the next workflow starts. - Use
entrypoints[].sequenceto declare the default journey entered by a route. - Use
transitions[].options[].sequencewhen a user choice must switch from the route's default journey into a different authored sequence. - Use
affected_declarative_familieson sequences when the builder control plane needs to derive artifact invalidation impact from the selected route. - Do not place a workflow in the same or earlier step as one of its required dependencies.
- If
Bdepends onA, author the sequence asAin an earlier step andBin a later step. - Do not list the same workflow more than once in a sequence.
- Entry UI belongs to
extension_registry.json -> entrypoints[]viatransition. The sequence may include the same transition as its first step so the journey contract remains fully ordered.
Brownfield Context Refresh¶
brownfield_discovery_refresh is the canonical sequence for resolving a Refinement Engine ContextRefreshPlan after stale brownfield context blocks a risky refinement. It reruns ExistingAppDiscovery only.
ContextRefreshPlan creation is planning-only. It does not start this sequence from stale-context policy evaluation, dry-run, or refinement routing. The sequence starts only when an operator or caller explicitly invokes launch_context_refresh_plan, which resolves the registered sequence and starts ExistingAppDiscovery through the normal workflow launch path.
This sequence is non-mutating by shape:
- it contains no
AppGeneratororAgentGeneratorstep - it creates no staged patch and no generated overlay
- it does not promote or mutate source repositories
- it refreshes app-context artifact families and registers a new
AppContextVersionthroughExistingAppDiscoverypersistence - when source files are available, it persists
source_context_bundlebeforeapp_context_graphso refinement tools can search and read exact code
It does not run AppGenerator, AgentGenerator, or DesignDocs.
After workflow completion, the Refinement Engine can call complete_context_refresh to compare the previous context version with the new current AppContextVersion and produce a ContextRefreshResult. That result records whether stale context was actually resolved. It does not relaunch workflows, mutate source repositories, or retry the blocked refinement automatically.
Brownfield generation/build sequences remain separate:
| Sequence | Purpose |
|---|---|
brownfield_app_adoption | Capture the app path choice first, then ask which repo to analyze, then run App Intelligence indexing and discovery chat with that scope already selected. |
brownfield_overlay_generation | User-facing Add AI Workflows path. Starts at ValueEngine, then generates approved app-aware AI workflows, chat surfaces, and required safe adapters while the existing app remains source of truth. |
brownfield_module_generation | User-facing Build App Features path. Starts at ValueEngine, then generates Mozaiks-owned modules, workflows, pages, data contracts, and extended functionality only for explicitly approved expansion scope. |
The brownfield_path_selector screen is the first brownfield decision after the app-type selector. It should frame Add AI Workflows as the normal first move for most existing apps. Build App Features is for intentional module and product expansion, not an automatic full-repository rewrite. Both choices route into brownfield_repo_input, which asks which repo to analyze before ExistingAppDiscovery starts. The selected internal value (light_integration or full_migration) becomes downstream scope context.
Brownfield App Intelligence UX¶
The existing-app intake path has two user-facing context surfaces:
ExistingAppDiscoverystreams a persistent inlineAppIntelligenceProgressCardfrom normalUI_Surfacetool-call events. When indexing reaches ready, that card collapses to a compact completed marker so the chat does not compete with the artifact panel. After thebefore_chatpreload completes and before the first agent message, it emitsAppIntelligenceOverviewCardin the artifact panel. The card renders the prompt-safe product readout: a concise app summary and major feature areas translated out of code terminology. It does not render raw source contents, graph metrics, source refs, scanner codes, or AI opportunity lists.ValueEngineowns enhancement recommendations after the user chooses an enhancement path.- The brownfield path now enters
brownfield_path_selectordirectly afterapp_type_selector, thenbrownfield_repo_input, thenExistingAppDiscoverywith the selected build path already set. The repo intake screen captures the source repo before discovery starts.
These surfaces are not AppPages. The progress card is inline workflow UI and AppIntelligenceOverviewCard is artifact workflow UI owned by ExistingAppDiscovery. The Refinement Engine consumes the same App Intelligence through checkpoint tools when the user later asks to revise or extend the app.
Existing-app discovery also materializes a local Studio app-registry record from the shared build lifecycle event. The build-events outbox still exists for hosted delivery, but /apps must not depend on that callback being configured: as soon as ExistingAppDiscovery starts, the imported repository appears as an in-progress app with a continue link back to the discovery chat.
Navigation Entry¶
The app shell enters a transition directly:
{
"entrypoints": [
{
"id": "create_app",
"path": "/create",
"label": "Create App",
"sequence": "build",
"transition": "app_type_selector"
}
]
}
Optional shell CTAs are declared separately in shell.json:
{
"header": {
"actions": [
{
"id": "create-app",
"intent": "create_app",
"label": "Create App",
"path": "/create"
}
]
}
}
If the CTA needs to change during an active workflow session, use semantic shell action variants in shell.json; do not put route override logic in the workflow registry.
RouteRenderer mounts TransitionScreen, and transition resolution calls /api/transitions/resolve. If the result is another transition, the shell mounts that transition. If the result is a workflow, the backend creates a chat session and the shell navigates to chat.
The shell forwards entrypoints[].sequence as journey_id when it starts a transition or workflow route. If a transition option declares its own sequence, that option-level sequence overrides the inherited route journey for the selected branch.
Context Hydration¶
Transitions write deterministic key/value seeds into accumulated journey context. The runtime does not mutate workflow files. Before a workflow chat session is created, context is filtered against the target workflow's declared context_variables.yaml definitions. AG2 receives only declared keys, and agent visibility remains controlled by that workflow's agents: exposure map.
Generator Rules¶
AgentGenerator may generate extension_registry.json, but it should default to:
workflows[]with explicit dependenciesworkflow_sequences[]only when auto-advance sequencing is requiredtransitions: []only when the generated app has no journey decisions
AgentGenerator may generate transition React stubs under extended_orchestration/ui when transition visuals need product branding. Persistent app pages still belong to AppGenerator schemas. Agent UI tools belong to workflow-local ui/ plus Python tools. If AgentGenerator emits a transition, it must keep routing/context deterministic and bind ui.component to a registered transition component key. Product-specific copy/images/layout belong in the React stub.