A flow you design in Heliox doesn’t have to stay in Heliox. Export it once, and the same DAG runs on any of three independent SDK runtimes — TypeScript, Java, or Python — with the execution semantics that matter (ordering, output, tool calls, loops) proven identical across all three.
The shape of the workflow
- Design a flow on the canvas or with Text-to-Flow (see Flow Design).
- Export it to a portable
HelioxFlowExport— a.flow.jsonfile. See API Reference for the exact schema. - Hand that file to whichever runtime fits your deployment: keep it in the desktop app and serve it (see Serve & Deploy), or load it directly from a Java or Python service you already run.
The export format is intentionally vendor-neutral: step ids, the dependency graph, prompts, flattened system prompts, tool names, contracts, and model overrides all round-trip exactly. It’s the interchange layer that lets one design surface (the canvas) feed three execution runtimes without re-authoring the flow per target language.
Running a flow per runtime
TypeScript
The TypeScript runtime is the one built into Heliox itself. The straightforward path is
heliox serve (see Serve & Deploy), which loads a .flow.json,
validates its DAG, and executes it on request. Programmatically, the same execution core is
importFlow (deserialize the export) followed by the flow executor that walks the DAG.
Java
The Java runtime (sdk/java in the heliox-ide repository, Maven coordinates
io.heliox:heliox-sdk-java, Java 21) centers on two classes:
HelioxRuntime— the entry point and dependency root. Configure it with a builder: an LLM provider, any@HelioxTool-annotated tool objects, optional registered flows, then call.flow(name)to begin an execution.FlowExecutor— orchestrates aFlowDefinitionas a DAG. Dependency-free steps start immediately; a dependent step’s future is composed asallOf(parents).thenCompose(...), so independent branches genuinely run concurrently while shared step outputs stay race-free in a concurrent map.execute()returns a single typed sink;executeMultiSink()supports multiple typed outputs;executeAllText()is the canonical path for schema-less flows (raw text per step, no JSON-schema extraction).
HelioxRuntime runtime = HelioxRuntime.builder()
.llmProvider(new OpenAiProvider(apiKey)) // or MimoProvider / a custom OpenAiCompatibleProvider subclass
.registerTool(new MyTools()) // @HelioxTool-annotated methods
.build();
var result = runtime.flow("my-flow")
.withContext("input", "some value")
.executeAsync();Build it locally with mvn install -f sdk/java/pom.xml to place heliox-sdk-java in your local
Maven repository, then depend on that coordinate from your own project.
Python
The Python runtime (sdk/python in the heliox-ide repository, package name heliox-sdk,
requires Python 3.10+, zero runtime dependencies) exposes FlowExecutor with the same shape as
its Java counterpart:
from heliox_sdk import FlowExecutor, FlowImport, StepExecutor
flow = FlowImport.from_canonical_file("my-flow.flow.json")
executor = FlowExecutor(StepExecutor(provider=my_provider))
trace = executor.execute_all_text_trace(flow)execute_all_text / execute_all_text_trace mirror the Java runtime’s executeAllText —
schema-less, raw per-step text output, in DAG order. Install it locally with
pip install ./sdk/python (or pip install -e sdk/python for development).
The conformance story
Three independently-implemented runtimes are only as trustworthy as their agreement with each other. Heliox’s SDKs are conformance-verified across TypeScript, Java, and Python for DAG order, text output, typed-output rule, tool-calling, and contract/model round-trip; loop parity proven in TS + Java.
That guarantee is backed by a shared set of golden fixtures (canonical .flow.json files, scripted
LLM responses, and expected traces) that all three runtimes’ test suites execute against:
| Guarantee | What’s actually checked |
|---|---|
| DAG order | All three runtimes reproduce the same deterministic topological order (Kahn’s algorithm, ties broken by step id ascending) over a shared canonical flow. |
| Text output | Byte-identical per-step text output for schema-less flows — proven against a shared golden trace, not just eyeballed. |
| Typed-output rule | Both runtimes propagate raw provider text by default; JSON-schema typed extraction is an explicit opt-in, never a silent default divergence between runtimes. |
| Tool-calling | A real tool is actually invoked in each runtime (not bypassed by a scripted shortcut) — same arguments in, same result threaded back, same post-tool output. |
| Contract/model round-trip | A step’s contract and per-step model override are carried opaquely through export/import and survive byte-for-byte, even though this format layer never interprets them. |
| Loop parity (TS + Java) | The bounded loop-back expansion algorithm produces the same per-iteration execution trace in both runtimes. |
Each runtime’s proof lives alongside its code: the TypeScript suite in
src/main/flow-export/*.test.ts, the Java suite in CrossRuntimeConformanceTest, and the Python
suite in sdk/python/tests/test_cross_runtime_conformance.py. All three must stay green before any
change to the shared fixtures merges.
Versioning
The export format itself is versioned (HelioxFlowExport.version, currently "1") independently
of each SDK’s own package version — a flow exported today stays loadable by future runtime
releases that support format version 1. Bounded loops in the wire format require heliox-sdk ≥
0.2.0 on the consuming side.