MentatLab docs
MentatLab Orchestrator Service: Core Architecture
Last updated: 2025-07-23
1. Introduction
This document outlines the core architectural design for the MentatLab Orchestrator service. The Orchestrator is a critical component responsible for interpreting a flow.mlab file, understanding its dependency graph, and generating a concrete execution plan.
The design is based on the specifications laid out in the docs/flows.md document, specifically the graph data structure and the runtime lifecycle.
2. Core Components
The Orchestrator is composed of a pipeline of four main components that progressively transform the raw Flow definition into an executable plan.
2.1. Parser/Loader
- Responsibility: Ingest and validate the
flow.mlabdata structure. - Input: A raw
Flowobject (JSON/YAML), typically received from the Gateway via aPOST /runsrequest. - Process:
- Deserializes the incoming JSON or YAML into an internal
Flowdata structure. - Validates the structure against the
schemas/flow.schema.json. This ensures all required fields (apiVersion,kind,meta,graph) are present and correctly typed. - Performs initial sanity checks, such as verifying that node IDs are unique.
- Deserializes the incoming JSON or YAML into an internal
- Output: A validated, in-memory
Flowobject.
2.2. DAG Processor
- Responsibility: Represent the flow's node and edge relationships as a formal Directed Acyclic Graph (DAG).
- Input: The validated
Flowobject from the Parser/Loader. - Process:
- Iterates through the
graph.nodeslist, creating a vertex in the DAG for each node. - Iterates through the
graph.edgeslist. For each edge, it creates a directed link from thefromnode to thetonode. The edge definition (from: prompt1.texttoto: llm1.text) is simplified to a node-to-node relationship (prompt1->llm1). - While processing, it detects cycles in the graph (e.g.,
A -> B -> A). If a cycle is found, the flow is invalid, and the process is aborted with an error.
- Iterates through the
- Output: An in-memory DAG data structure (e.g., using a library like Python's
networkxor a custom graph implementation) representing the flow's execution dependencies.
2.3. Topological Sorter
- Responsibility: Determine the correct, dependency-aware execution order of the nodes.
- Input: The DAG from the DAG Processor.
- Process:
- Applies a topological sorting algorithm (e.g., Kahn's algorithm or depth-first search) to the DAG.
- The algorithm identifies nodes with no incoming edges (source nodes) and adds them to the sorted list.
- It then "removes" these nodes and their outgoing edges from the graph, and repeats the process until all nodes have been visited.
- Output: A linearly ordered list of node IDs, representing the sequence in which nodes can be executed. Parallelizable branches will appear adjacent in the list but can be identified by analyzing their dependencies.
2.4. Execution Planner
- Responsibility: Generate a simple, step-by-step execution plan from the sorted graph.
- Input: The topologically sorted list of node IDs.
- Process:
- Transforms the sorted list into a simple, serializable data structure. This plan is the final artifact the Orchestrator produces before handing off to the execution engine (e.g., Kubernetes Job creator).
- The plan could be a simple array of steps, where each step contains one or more node IDs that can be executed in parallel.
- Output: An execution plan. For example:
In a more complex graph with parallel branches, it might look like:{ "plan": [ ["prompt1"], ["llm1"], ["console1"] ] }{ "plan": [ ["inputA", "inputB"], ["processA", "processB"], ["aggregator"] ] }
3. Process Flow Diagram
The following diagram illustrates how a Flow object is processed through the Orchestrator's components to produce an execution plan.
graph TD
subgraph Orchestrator Service
A[1. Parser/Loader] --> B[2. DAG Processor];
B --> C[3. Topological Sorter];
C --> D[4. Execution Planner];
end
subgraph Inputs
FlowFile["flow.mlab <br/>(JSON/YAML)"];
end
subgraph Outputs
ExecPlan["Execution Plan <br/>(e.g., [['A'], ['B', 'C'], ['D']])"];
end
FlowFile --> A;
D --> ExecPlan;
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
## 4. Execution Plan API Surface
Endpoints (examples):
- POST /runs
- Query param: mode=plan|redis|k8s
- If mode=plan: returns execution plan JSON (topologically grouped steps)
- If mode=redis or k8s: enqueues run and returns runId; events stream via WS/SSE
- GET /runs/{runId}/checkpoints
- Returns list of checkpoints for run
- GET /runs/{runId}/events
- Stream of Recorder/Orchestrator events (SSE or WS)
Notes:
- plan mode is intended for dry-run planning & preflight validation
- redis mode publishes tasks to Redis stream `agent_tasks:<agent_id>`
- k8s mode schedules Jobs / Deployments (production)
Status: If code stubs exist, add anchor(s) to [`docs/status/anchors.json`](docs/status/anchors.json:1) (current status: planned; see `schemas.flow` and orchestrator stubs in [`docs/status/project-status.yaml`](docs/status/project-status.yaml:1))