Flows
Most machines have a single linear sequence of steps. For those, you place steps directly under implements and the runtime executes them in order. When a machine needs multiple execution paths, parallel processing stages, or reusable step groups, you use named flows.
Implicit main flow
For single-flow machines, put steps directly under implements:
implements ask classify, using: "anthropic:claude-haiku-4-5" with task "Classify this text" returns category as text assuming category: "general"
compute format {result: steps.classify.category}No flow keyword needed. This is the implicit main flow.
Named flows
When you need multiple execution paths, wrap them in a flows container:
implements flows flow extract ask fetch, from: "@mashin/actions/http/get" url: input.source_url assuming body: {records: []} status: 200
flow transform compute normalize {cleaned: steps.fetch.body.records.filter(r => r != null)}
flow load ask store, from: "@myorg/data/writer" records: normalize.cleaned assuming written: true compute result {status: "complete", count: normalize.cleaned.length}Each flow is a named group of steps. Flows execute in the order they are declared unless you use run or goto to control the sequence.
run and goto
run flow(name) calls a flow and returns to the current position (like a function call). goto flow(name) jumps to a flow and does not return (tail call).
implements compute check {needs_retry: input.attempt < 3}
decide route when check.needs_retry run flow(process) otherwise run flow(fallback)
flows flow process ask analyze, using: "anthropic:claude-sonnet-4-6" with task "Analyze this data" returns result as text assuming result: "Analysis complete"
flow fallback compute default_response {result: "Max retries exceeded", status: "failed"}Use run when you need to return and continue execution. Use goto when the current flow is done and execution should continue in another flow.
decide with flows
The most common pattern: use a decide step to route to different flows.
machine order_handler
accepts order_type as text, is required amount as number, is required
responds with status as text handler as text
implements decide route_order when input.order_type == "subscription" run flow(handle_subscription) when input.amount > 10000 run flow(handle_enterprise) otherwise run flow(handle_standard)
flows flow handle_subscription compute result {status: "processed", handler: "subscription_team"}
flow handle_enterprise compute result {status: "pending_review", handler: "enterprise_sales"}
flow handle_standard compute result {status: "processed", handler: "auto"}Error handling per flow
Each flow can have its own on failure block:
implements flows flow fetch ask get_data, from: "@mashin/actions/http/get" url: input.url assuming body: {} status: 200 on failure compute fetch_error {status: "fetch_failed", error: error.message}
flow process ask analyze, using: "anthropic:claude-sonnet-4-6" with task "Analyze: ${steps.get_data.body}" returns result as text assuming result: "OK" on failure compute process_error {status: "analysis_failed", error: error.message}If a step in fetch fails, only the fetch flow’s error handler runs. The process flow’s error handler is independent.
When to use multiple flows
Use named flows when:
- A
decidestep routes to different multi-step paths - An ETL pipeline has distinct extract, transform, and load stages
- You want independent error handling for different parts of the machine
- Steps are logically grouped and the grouping aids readability
Keep a single implicit flow when:
- Steps execute linearly from top to bottom
- There are fewer than 6 steps
- There is no branching or error isolation needed
Try it
Build an ETL machine with three named flows: extract (fetch data via HTTP), transform (clean and reshape with compute), and load (store via a machine call). Add on failure to each flow with different error responses.
Next steps
- Error Handling - Error recovery in depth
- Decisions - Routing logic with decide
- implements reference - Full specification
- run reference - Flow execution