Convert a Windmill flow to a Claude routine. What it cannot carry over is listed, not guessed.
RoutineOS is a Windmill alternative for jobs where a person reads something and decides. Export your flow as OpenFlow JSON, run one command, and you get a routine pack plus a file called MIGRATION.md that lists what a person still has to finish. It is free (MIT) and needs a paid Claude plan.
What the Windmill converter carries over
The converter is deterministic Python. It reads OpenFlow, the JSON format for a Windmill flow, and writes a pack plus a report. It reads paths and names only, never a secret value.
| In the Windmill flow | In RoutineOS |
|---|---|
| A raw script module (TypeScript, Python, Bash and others) | A code stage. Your original source is kept in lib/source/ and is never run. |
| A script or flow referenced by path | A step marked "needs a person", with the path named. |
| For loops and while loops | The inner steps are listed after it and marked "for each item". |
| Branches | The branches are listed and marked by their summary. |
| AI agent module | A skill stage. The system prompt and user message are used when they are static. |
| AI decision module | A model stage. |
| A suspend step (approval) | An approval gate stage placed after that step and before the next one. |
| Failure module | Failure handling. |
| Flow input schema | Settings: a boolean becomes a toggle, a number a number, an enum a choice, a list of strings a list. The rest is reported. |
| Resources and variables | Listed by path only. You re-create each value yourself. A resource whose name matches a known app also gets an unverified connector. |
| Values from earlier steps and flow input | Explicit inputs, such as "x from step a" or "Setting y". |
What is refused, and what a person finishes
Refused or stopped
- YAML. A
flow.yamlfile is refused with a message to export the flow as JSON, because the converter has no YAML parser. Whether the Windmill app exports JSON is unverified. - An inconsistent input. A number input whose minimum is above its maximum stops the conversion and names the input.
- A file it cannot read. It ends with "this workflow could not be converted", exit code 2 and no output.
A person finishes
- The schedule. A flow file carries no schedule. The default (weekdays at 22:00 UTC) applies and is reported as needing a person. Give the real cron, in UTC, at most hourly.
- Code. The skill translates it to a Python 3.11 standard library script, or you replace it with a model step.
- Resources and variables. Re-create each one and reconnect apps on claude.ai.
- Referenced scripts and flows. Each becomes a "needs a person" step.
Convert a Windmill flow with one command
Give it the exported JSON file and a folder that does not exist yet (or is empty). Or paste the flow into Claude Code and ask Claude to use the routineos-migrate skill.
- You get two files
pack.jsonandMIGRATION.md, in the folder you named. - Read the exit code0 means nothing needs a person. 1 means the pack was written and the report lists items for a person. 2 means it failed.
- Check, then installValidate the pack, install it, then run it once report-only before you trust it.
When to keep Windmill
- Nothing in the job needs a judgment call. A fixed flow runs fine as a fixed flow.
- You need it to react in seconds. A routine runs on a schedule of an hour or more, in UTC.
- You do not use Claude. A routine runs on a paid Claude plan.
- You need a settled platform. Claude scheduled tasks are a research preview.
You can also keep Windmill for the plumbing and move only the step that reads and decides. If you also run n8n, see the n8n comparison, or all comparisons and the templates.
Convert a flow
Export it as OpenFlow JSON, run the command, and read MIGRATION.md before you turn anything on.