Skip to main content

Getting started

This walks through running your first workflow — a tiny one that takes an input parameter and produces a result.

Add the dependency

<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-workflow</artifactId>
<version>0.5.0</version>
</dependency>

That's the whole engine. No Spring, no server.

A simple workflow in Java

Build a WorkflowData, add a step that assigns a variable, and execute it:

import ai.mindconnect.workflow.domain.AssignVariablesData;
import ai.mindconnect.workflow.domain.VariableAssignment;
import ai.mindconnect.workflow.domain.WorkflowData;
import ai.mindconnect.workflow.execution.DefaultWorkflowContextFactory;
import ai.mindconnect.workflow.execution.WorkflowExecutorService;
import ai.mindconnect.workflow.execution.WorkflowResult;

import java.util.Map;

public class Demo {
public static void main(String[] args) {
// 1. One step: greeting = "Hello, ${name}!"
var greet = new AssignVariablesData();
greet.setName("greet");
greet.getVariableAssignments()
.add(new VariableAssignment("greeting", "Hello, ${name}!"));

// 2. The workflow: one step, result taken from the 'greeting' variable
var wf = new WorkflowData();
wf.setName("hello");
wf.addSteps(greet);
wf.setResultFrom("greeting");

// 3. Run it with input parameters
var service = new WorkflowExecutorService(new DefaultWorkflowContextFactory());
WorkflowResult result = service.executeWorkflow(wf, Map.of("name", "Ada"));

System.out.println(result.isSuccess()); // true
System.out.println(result.getResult()); // Hello, Ada!
}
}

${name} is resolved from the input parameters; setResultFrom("greeting") tells the workflow which variable to return as its result.

Add a computed step (scripting)

To compute values, use a script expression — a value prefixed with a language name, like mini: base * base.

MiniScript — built in, no dependency

The engine always has the MiniScript language registered out of the box (language name mini), so you can compute without adding anything:

var square = new AssignVariablesData();
square.setName("square");
square.getVariableAssignments()
.add(new VariableAssignment("result", "mini: base * base"));

var wf = new WorkflowData();
wf.setName("square");
wf.addSteps(square);
wf.setResultFrom("result");

var result = new WorkflowExecutorService(new DefaultWorkflowContextFactory())
.executeWorkflow(wf, Map.of("base", 7));
// result.getResult() -> 49.0 (MiniScript arithmetic always yields a Double)

MiniScript is a small, JSON-friendly expression language — see the MiniScript reference for its full syntax.

Other languages (Groovy, BeanShell, Jython)

For Groovy, JavaScript, BeanShell or Jython, add that language module plus mc-workflow-spi-lookup (which auto-registers every module on the classpath). For example, Groovy:

<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-workflow-code-groovy</artifactId>
<version>0.5.0</version>
</dependency>
<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-workflow-spi-lookup</artifactId>
<version>0.5.0</version>
</dependency>

Build the factory with SpiWorkflowContextFactory.create() — it discovers and applies the Groovy module automatically, so there is no manual configure(...) call. Then prefix the expression with groovy::

import ai.mindconnect.workflow.spi.SpiWorkflowContextFactory;

// Picks up mc-workflow-code-groovy (and any other module) from the classpath
var ctx = SpiWorkflowContextFactory.create();

var square = new AssignVariablesData();
square.setName("square");
square.getVariableAssignments()
.add(new VariableAssignment("result", "groovy: base * base"));

var wf = new WorkflowData();
wf.setName("square");
wf.addSteps(square);
wf.setResultFrom("result");

var result = new WorkflowExecutorService(ctx)
.executeWorkflow(wf, Map.of("base", 7));
// result.getResult() -> 49

mc-workflow-code-javascript, -beanshell, -jython and mc-workflow-jackson register themselves the same way — no wiring code required. See How it works → Auto-registration (SPI).

Or author it in PlantUML

With mc-workflow-dsl-puml, the same assignment workflow is a diagram:

@startuml hello
:assign greet
greeting = Hello, ${name}!
assign-result -> greeting
;
@enduml
import ai.mindconnect.workflow.dsl.puml.PumlWorkflowParser;

WorkflowData wf = new PumlWorkflowParser().parse(pumlString);
var result = new WorkflowExecutorService(new DefaultWorkflowContextFactory())
.executeWorkflow(wf, Map.of("name", "Ada"));

Or define it as JSON

With mc-workflow-jackson a workflow is a plain JSON document. Add the module:

<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-workflow-jackson</artifactId>
<version>0.5.0</version>
</dependency>

Write the workflow — the @class fields are the type discriminators that tell Jackson which step type each node is (hello.json):

{
"@class": "ai.mindconnect.workflow.domain.WorkflowData",
"name": "hello",
"resultFrom": "greeting",
"params": [ "name" ],
"steps": [ {
"@class": "ai.mindconnect.workflow.domain.AssignVariablesData",
"name": "greet",
"assignResultToVar": "greeting",
"variableAssignments": [ {
"varName": "greeting",
"expressionOrVarName": "Hello ${name}!"
} ]
} ]
}

Read it with JacksonWorkflowSerializer and execute it like any other WorkflowData:

import ai.mindconnect.workflow.jackson.JacksonWorkflowSerializer;
import ai.mindconnect.workflow.jackson.WorkflowObjectMapperFactory;
import ai.mindconnect.workflow.execution.DefaultWorkflowContextFactory;
import ai.mindconnect.workflow.execution.WorkflowExecutorService;

import java.nio.file.Path;
import java.util.Map;

var serializer = new JacksonWorkflowSerializer(WorkflowObjectMapperFactory.create());

// read(String json), read(Path), read(InputStream), or readFromClasspath(...)
WorkflowData wf = serializer.read(Path.of("hello.json"));

var result = new WorkflowExecutorService(new DefaultWorkflowContextFactory())
.executeWorkflow(wf, Map.of("name", "Jackson"));
// result.getResult() -> Hello Jackson!

serializer.write(workflowData) does the reverse — turn a WorkflowData you built in Java into JSON, so you can design in code and persist as JSON (or vice versa).

Next

  • Add control flow with IfStep and ForEachStep.
  • Call one workflow from another with CallWorkflowStep.
  • Pause and resume with mc-workflow-persistence.

See How it works for the full step catalogue.