Skip to content

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:

{
  "extends": "mozaiks.default_workflow_registry"
}

The OSS loader then builds one effective registry:

  • workflows[], entrypoints[], workflow_sequences[], and transitions[] merge by id.
  • { "id": "...", "remove": true } removes an inherited item.
  • artifact_dependency_graph merges 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", and handoff_style: "continuous_chat".
  • Standalone manual workflow starts may use launch_behavior: "wait_for_user" and handoff_style: "separate_chat" when a blank chat is intentional.
  • Domain-event workflows use startup_mode: "BackendOnly", interaction_mode: "backend_only", launch_behavior: "none", and handoff_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:

<workflow>/extended_orchestration/task_batches.yaml

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 from ui/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_transition on workflow sequence declarations.
  • Do not put product-specific presets such as dogfood shortcuts in the global transition schema.
  • Transition context_variables may seed deterministic context only when the target workflow declares those keys in context_variables.yaml.
  • Use entrypoints[] entries with transition: <id> to enter a transition screen.
  • Transition entry routes should use meta.shellMode: "focused" and transition UI should use ui.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_to can point to another transition id.
  • route_to can point to a workflow id.
  • The loader stamps route_type internally after validation.
  • Transition UI emits option_id; it does not emit route_to.
  • All user choice transitions declare route_to on each option.
  • Use user_choice_context when the main point is deterministic context seeding, even if multiple options still route to the same next step.
  • Use user_choice_route when the main point is branch routing across different targets.
  • options[].context_variables is merged into the accumulated transition context before target workflow creation.
  • The workflow start path filters context against the target workflow's context_variables.yaml definitions.
  • 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:

factory_app/workflows/extended_orchestration/ui/index.js

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:

{
  "id": "app_review",
  "transition_type": "chat_session",
  "route_to": "AppReview"
}

Rules:

  • route_to is required and must point to a registered workflow id.
  • chat_session transitions must NOT declare a ui block — they never render an overlay component.
  • confirm_route, cancel_route, options, context_key, and routes are not valid on chat_session transitions.

Runtime behavior:

  1. The sequence auto-advances to the chat_session transition after the preceding workflow completes.
  2. TransitionScreen receives the transition, detects chat_session, and immediately calls onResolve(null) without mounting any UI.
  3. The shell calls /api/transitions/resolve and receives resolution_type: "chat_session" with chat_id, workflow_id, and the filtered context_variables from the active journey.
  4. The shell switches the active chat session in-place to the launched workflow — no navigation away, no overlay, no blocked input.
  5. The target workflow receives the accumulated journey context_variables filtered against its own context_variables.yaml declarations.

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:

{
  "id": "AppGenerator",
  "dependencies": ["DesignDocs", "AgentGenerator"]
}

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[].sequence to declare the default journey entered by a route.
  • Use transitions[].options[].sequence when a user choice must switch from the route's default journey into a different authored sequence.
  • Use affected_declarative_families on 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 B depends on A, author the sequence as A in an earlier step and B in a later step.
  • Do not list the same workflow more than once in a sequence.
  • Entry UI belongs to extension_registry.json -> entrypoints[] via transition. 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 AppGenerator or AgentGenerator step
  • 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 AppContextVersion through ExistingAppDiscovery persistence
  • when source files are available, it persists source_context_bundle before app_context_graph so 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:

  1. ExistingAppDiscovery streams a persistent inline AppIntelligenceProgressCard from normal UI_Surface tool-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 the before_chat preload completes and before the first agent message, it emits AppIntelligenceOverviewCard in 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. ValueEngine owns enhancement recommendations after the user chooses an enhancement path.
  2. The brownfield path now enters brownfield_path_selector directly after app_type_selector, then brownfield_repo_input, then ExistingAppDiscovery with 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 dependencies
  • workflow_sequences[] only when auto-advance sequencing is required
  • transitions: [] 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.