Lesson 5: Module 05: Control Flow and Loops
このコンテンツはまだ日本語訳がありません。
Chain steps together, branch conditionally, and build iterative pipelines.
Learning Objectives
Section titled “Learning Objectives”- Organize steps into named flows (a named sequence of steps)
- Use multiple flows for organization and control
- Branch with
decidesteps for conditional routing - Iterate with control flow patterns
Complexity Ladder: Levels 2-4 (Conditional, Iterative, Resilient); branching, loops, and error handling.
The Concept: Controlling the Flow
Section titled “The Concept: Controlling the Flow”Until now, our machines have been linear: Step A, then Step B, then Step C. Real workflows need branching (“if this, do that”), routing (“send billing issues here, support issues there”), and iteration (“process each item”). Mashin provides all of these through chains and control flow constructs.
Think of chains as chapters in a recipe book. The main chapter (:main) is your starting point. You can reference other chapters (run) — follow those instructions, then come back. Or you can jump to a chapter (goto) — like “start over from step 1” without coming back.
Chains are named sequences of steps. Every machine has at least one flow — :main — which is the entry point. You can define additional chains for organization, error handling, or looping.
Here is how run (call-and-return) and goto (tail-call / jump) differ visually:
run flow(:process) goto flow(:iterate) (Call-and-return) (Tail-call / jump)
flow :main flow :iterate ┌─────────────────┐ ┌─────────────────┐ │ step :setup │ │ step :work │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ run :process ───┼──► flow :process │ goto :iterate ──┼──┐ │ │ │ (runs, then │ │ │ │ ▼ │ returns here) │ step :never_runs│ │ │ step :finalize │ │ (unreachable!) │ │ └─────────────────┘ └─────────────────┘ │ ▲ │ └──────────────┘ (loops back)Notice that run returns to the calling flow so the next step (:finalize) can execute, while goto jumps away permanently — any steps after it are unreachable.
Start With Koda
Section titled “Start With Koda”Koda requires a free account. Sign in or create an account to use Koda exercises throughout this course. If you’re not signed in yet, read on; the exercises will be here when you’re ready.
Ask Koda:
“Build a machine that processes a list of URLs. For each URL, fetch the content and summarize it. If a fetch fails, skip that URL and continue with the next one.”
Check that Koda uses for_each (iterate over each item in a list) for iteration and proper error handling. The machine should use loop(:item) (access the current element in a for_each loop) inside the for_each block to access each URL.
Chains and Chain Control
Section titled “Chains and Chain Control”Multiple Chains
Section titled “Multiple Chains”machine processor "Pipeline Processor"
accepts data as string, is required
responds with result as map
behaves flows flow main compute validate {valid: length(input.data) > 0}
ask process_data, using: "anthropic:claude-haiku-4" with task "Process this data: ${input.data}" returns output as map
compute finalize {result: steps.process_data.output}
flow process ask process_data, using: "anthropic:claude-haiku-4" with task "Process this data: ${input.data}" returns output as map
verifies test "processes data through the main flow" assuming process_data {output: {cleaned: true}} given {data: "raw data"} expect {result: {cleaned: true}}run vs goto
Section titled “run vs goto”These two control flow primitives have critically different behavior:
Multiple flows are used for organization and modularity.
Conditional Execution
Section titled “Conditional Execution”decide Steps
Section titled “decide Steps”Use decide steps for conditional routing:
decide route_by_severity when steps.check.severity == "critical" ask alert, from: "@mashin/actions/http/post" url: "https://alerts.example.com/critical" otherwise compute log_info {logged: true}Branching Patterns
Section titled “Branching Patterns”decide process_or_reject when steps.validate.valid == true ask process, using: "anthropic:claude-haiku-4" with task "Process: ${input.data}" otherwise compute reject {error: "Invalid input", rejected: true}Multi-Way Routing
Section titled “Multi-Way Routing”Route execution based on a value:
decide route_by_format when input.output_format == "summary" ask summarize, using: "anthropic:claude-haiku-4" with task "Summarize: ${input.text}" when input.output_format == "structured" ask extract, using: "anthropic:claude-sonnet-4" with task "Extract structured data from: ${input.text}" returns entities as list topics as list otherwise compute passthrough {result: input.text}Building It: Multi-Step Pipeline with Branching
Section titled “Building It: Multi-Step Pipeline with Branching”A document processor that validates, routes by format, and handles errors:
machine document_pipeline "Document Pipeline"
accepts document as string, is required format as string
responds with result as map format_detected as string
behaves compute validate {valid: length(input.document) > 10}
ask detect_format, using: "anthropic:claude-haiku-4" with task "What format is this document? Options: markdown, json, plain.\n\n${input.document}" returns format as string
compute resolve_format {format: input.format != "auto" ? input.format : steps.detect_format.format}
decide route_by_format when steps.resolve_format.format == "json" compute process_json {result: {type: "json", parsed: true}, format_detected: "json"} when steps.resolve_format.format == "markdown" ask process_markdown, using: "anthropic:claude-haiku-4" with task "Extract headings and structure from this markdown:\n${input.document}" returns headings as list sections as number otherwise ask process_plain, using: "anthropic:claude-haiku-4" with task "Summarize this plain text document:\n${input.document}" returns summary as string
verifies test "routes json documents down the json path" assuming detect_format {format: "json"} given {document: "{\"a\": 1, \"b\": 2}", format: "json"} expect {format_detected: "json", result: {type: "json", parsed: true}}Key Syntax
Section titled “Key Syntax”// Flow definition (under behaves)behaves flows flow name // steps go here
// Single flow (implicit, no flows wrapper needed)behaves compute step_a {result: "done"}
// Decide step for branchingdecide name when condition // steps for this branch otherwise // fallback stepsCommon Mistakes
Section titled “Common Mistakes”-
Overcomplicating control flow. Keep flows linear when possible. Use
decidesteps only when you need conditional routing based on runtime values. -
Infinite loops without limits. Always include a check-and-exit condition for iterative flows. The flow depth limit (100) will catch runaway loops, but your logic should stop before that.
What’s Next
Section titled “What’s Next”In Module 06, you’ll combine everything from Modules 01-05 to build a full ReAct (Reason-Act-Observe) agent, the loop pattern that powers autonomous AI systems.