RoutineOSBeta
Compare / Windmill

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.

Converter builtFree (MIT). Needs a paid Claude plan.Converted routines are unpiloted
What converts

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 flowIn 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 pathA step marked "needs a person", with the path named.
For loops and while loopsThe inner steps are listed after it and marked "for each item".
BranchesThe branches are listed and marked by their summary.
AI agent moduleA skill stage. The system prompt and user message are used when they are static.
AI decision moduleA model stage.
A suspend step (approval)An approval gate stage placed after that step and before the next one.
Failure moduleFailure handling.
Flow input schemaSettings: 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 variablesListed 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 inputExplicit inputs, such as "x from step a" or "Setting y".
Any step that writes is gatedIf a step sends, posts or writes to an app, the converted routine is approval-gated and that step moves after the gate. Do not remove the gate to match the original. A converted routine starts report-only and unpiloted.
What it refuses or needs from you

What is refused, and what a person finishes

Refused or stopped

  • YAML. A flow.yaml file 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.
The command

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.

$ python3 skills/routineos/scripts/routineos.py migrate windmill <flow.json> --out <dir>
  1. You get two filespack.json and MIGRATION.md, in the folder you named.
  2. 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.
  3. Check, then installValidate the pack, install it, then run it once report-only before you trust it.
When to keep Windmill

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.