MiniScript reference
MiniScript is a small, zero-dependency expression language built into the
workflow engine. It is always registered (language name mini), so
mini:-prefixed expressions work without adding any mc-workflow-code-*
module. It is also a standalone JSR-223 engine (mc-script-mini) you can use on
its own.
Its sweet spot is JSON-shaped data: list and map literals, dot/index access, and the handful of operators and built-ins you need to compute and decide — nothing more.
In a workflow
Prefix any expression with mini::
new VariableAssignment("greeting", "mini: \"Hello \" + name + \"!\"")
new VariableAssignment("total", "mini: price * qty")
In an IfStep condition:
cond.setCondition("mini: score >= 90");
Syntax
Comments and primitives
// a comment
x = 42
name = "hello"
flag = true
Lists and maps
// list literal -> java.util.ArrayList
ids = ["a", "b", "c"]
nums = [1, 2, x + 1]
// map literal -> java.util.LinkedHashMap
person = { id: "1", name: "David", age: 40 }
mixed = { "key-with-dash": 99, nested: { x: 1 } }
Access
first = ids[0]
last = ids[-1] // negative index on lists
third = nums[x - 1]
david = person["name"] // string key
david2 = person.name // dot-access (same thing)
deep = data.user.tags[1] // nested
Operators
== != < > <= >= comparison
&& || ! logical
+ - * / arithmetic ( + also concatenates strings )
Conditionals
if (config.env == "prod" && !config.debug) {
println("Production, debug off")
} else if (config.debug) {
println("Debug mode")
} else {
println("Other")
}
Variables and scope
MiniScript has no block scoping — every assignment goes into one flat,
script-wide scope. There is no let/var and no per-block isolation:
if (flag) {
msg = "yes" // not local to the if — visible afterwards
}
println(msg) // works; "msg" leaked out of the block
This includes loop variables: the item (and index) of a for-each stay
defined after the loop, holding their last value. Reuse a name and you overwrite
the outer one.
for (item in items) { ... }
println(item) // still defined — the last element
In a workflow, the script's variables are bound from / written back to the
step's workflow variable scope (a CodeStep with the
default injectVariables / exportVariables). The hierarchical workflow scoping
applies at that boundary — but within a single MiniScript snippet everything is
flat.
Loops
for-each works over a List, array, Map or String:
for (item in items) {
println(item)
}
// with index
for (item, i in items) {
println(i + ": " + item)
}
// a for loop's value is the list of each iteration's last expression
doubled = for (n in nums) { n * 2 }
Calling Java methods
Values passed in from Java can be used directly — methods and JavaBean properties both work:
result = order.process(x, "arg")
size = ids.size()
status = order.status // calls getStatus() automatically
Built-ins
print(...) println(...) output
str(x) to string
num(x) to number
bool(x) to boolean
len(x) length of list / map / string
Standalone (JSR-223)
Outside the workflow engine, MiniScript is a normal JSR-223 engine — obtain it by name or via the factory:
import javax.script.ScriptEngine;
import ai.mindconnect.script.mini.MiniScriptEngineFactory;
ScriptEngine engine = new MiniScriptEngineFactory().getScriptEngine();
engine.put("order", myOrder); // expose a Java object
engine.eval("""
summary = { count: len(order.items), label: "items" }
""");
@SuppressWarnings("unchecked")
Map<String,Object> summary = (Map<String,Object>) engine.get("summary");
// read computed values straight back into Java
Note that arithmetic always returns a Double — 7 * 7 is 49.0, not 49.
(The module ships no META-INF/services entry for ScriptEngineFactory, so
ScriptEngineManager does not discover it automatically — instantiate
MiniScriptEngineFactory directly, as above. The workflow engine registers it
explicitly for the same reason.)