Skip to content
RoutineOS
Esc
↑↓navigate↵open⌘Jpreview
On this page

Migrate from Windmill

Convert a Windmill flow, as OpenFlow JSON, into a routine pack. How modules map and what is kept for a person.

routineos migrate windmill <flow.json> --out DIR reads a Windmill flow as OpenFlow JSON. See the overview.

OpenFlow is a JSON-serialisable standard for flows as DAGs. The OpenAPI file in the Windmill repository is the source of truth (https://raw.githubusercontent.com/windmill-labs/windmill/main/openflow.openapi.yaml, described at https://www.windmill.dev/docs/openflow). The root has summary, an optional description, value (with modules) and an optional schema for the flow input.

Mapping

OpenFlow Concept Becomes
rawscript step.code a code stage; language picks the extension and content is kept as source
script, flow (by path) step.subworkflow needs a person; the path is named
forloopflow, whileloopflow step.loop the inner modules are flattened after it and marked “for each item”
branchone, branchall step.branch the branches are flattened and marked by branch summary
identity step.noop dropped, recorded as info
aiagent step.agent a skill stage; system prompt and user message are used when static
aidecision step.branch a model stage
suspend on a module step.wait-approval a gate stage after that module (and after its inner modules, for a loop or branch), before the next step. Unverified, see below
failure_module failure.workflow failure handling
schema.properties settings boolean to toggle, number or integer to number, enum to choice, string array to list; the rest is reported
$res:path in a static transform credential by path only; a resource name that matches a known app also gets an unverified mcp connector, otherwise a setup issue
$var:name in a static transform credential by path only, plus a setup issue: re-create the value yourself
results.x, flow_input.y in javascript transforms expression explicit inputs: “x from step id”, “Setting y”

Resources and variables are referenced with $res:PATH and $var:NAME placeholders (https://www.windmill.dev/docs/core_concepts/resources_and_types). The converter reads only the path, never a value.

Suspend and approval

Where the gate goes is unverified. The Windmill approval page (https://www.windmill.dev/docs/flows/flow_approval, fetched 2026-10-30) calls an approval step “a normal script with Suspend until approval/resume enabled in the step’s Run settings tab”, says to “include the resume url in the returned payload of the step”, and says the flow “will not proceed to the next step” until the required approvals arrive. That implies the module runs first and the flow suspends after it, so the converter puts the gate after the module. The page does not say this in so many words. The emitter still moves every write stage after the gate, so a write step is not run before approval in the converted routine.

Source checks

A number input whose minimum is above its maximum stops the conversion with a message that names the input, because the flow’s own schema is inconsistent. A malformed file that the parser cannot read ends in exit 2 with “this workflow could not be converted” and no traceback.

Schedule

A flow file carries no schedule: schedules are separate objects and are not synced by default (https://www.windmill.dev/docs/advanced/cli/sync). The default schedule 0 22 * * 1-5 applies, and the emitter reports it as a needs-person issue. Ask the person for the real cron, in UTC.

YAML

flow.yaml is refused with a message to export the flow as JSON, because the Python standard library has no YAML parser. A synced flow lives at <path>__flow/flow.yaml (same sync page), so a person with a synced repository needs the JSON export. That the Windmill UI exports JSON is unverified.

Code

rawscript content can be TypeScript, Python, Bash and others. It is kept in lib/source/ and never run. The skill translates it to a Python 3.11 standard library script or replaces it with a model step. See n8n for the stub.

Licence

The GitHub API reported the Windmill licence as NOASSERTION on 2026-10-30 (https://api.github.com/repos/windmill-labs/windmill). The licence text was not read: unverified. Converting your own flow is unaffected.

Was this page helpful?