Computation
compute steps are the workhorse of mashin. They handle data transformation, calculation, formatting, and output construction. They use the mashin expression language (JavaScript-inspired) and are pure by construction: they cannot perform I/O, call external services, or access the network. This purity is not enforced by a sandbox. The capability simply does not exist.
Basic syntax
compute <name> <expression>The expression body is evaluated and its result becomes the step’s output. The last expression is the return value:
compute greet {greeting: "Hello, " + input.name + "!"}When to use compute
Use compute when you need to:
- Transform data from inputs or previous steps
- Calculate values (totals, averages, scores)
- Build the final output of a machine
- Format or reshape data structures
- Apply conditional logic with ternary expressions
Do not use compute for anything that requires external interaction. Use ask ... using for LLM reasoning. Use ask ... from for calling other machines. Use action for HTTP, database, or file operations.
Using let bindings
Break complex expressions into readable steps with let:
compute analyze let items = input.orders.filter(o => o.status == "completed") let total = items.reduce((sum, o) => sum + o.amount, 0) let count = items.length let average = count > 0 ? total / count : 0 { completed_count: count, total_revenue: total, average_order: average, above_average: items.filter(o => o.amount > average).length }Each let binding is scoped to the current step.
Referencing previous steps
Access results from earlier steps with steps.<name>.<field>:
machine pipeline
implements ask classify, using: "anthropic:claude-sonnet-4-6" with task "Classify this text" returns category as text confidence as number assuming category: "technology" confidence: 0.92
compute format let label = steps.classify.category let score = steps.classify.confidence { label: label, score: score, summary: label + " (confidence: " + score + ")" }Conditional values
Use the ternary operator for inline conditionals:
compute categorize let amount = input.amount { tier: amount > 10000 ? "enterprise" : amount > 1000 ? "business" : "starter", needs_review: amount > 5000, formatted: "$" + amount.toString() }For more complex branching, use a decide step instead. See Decisions.
Common patterns
Combining results from multiple steps
compute combine_results { sentiment: steps.analyze_sentiment.label, topics: steps.extract_topics.topics, summary: steps.summarize.text, processed_at: now() }Filtering and mapping
compute filter_high_priority let urgent = steps.classify.items.filter(i => i.priority == "urgent") let names = urgent.map(i => i.name) { urgent_items: urgent, urgent_names: names, urgent_count: urgent.length }Building output from input
compute normalize let cleaned = input.text.trim() let words = cleaned.split(" ").filter(w => w.length > 0) { original: input.text, cleaned: cleaned, word_count: words.length, preview: words.slice(0, 10).join(" ") + (words.length > 10 ? "..." : "") }Governance
Compute steps are pure by construction (Law I). They:
- Never require governance approval
- Never appear in permission checks
- Always execute, regardless of trust level
- Are safe to run in any mode (full, test, simulate)
This is why a machine with only compute steps does not need an ensures section. There is nothing to govern.
Try it
Write a machine that accepts a list of products (each with a name, price, and quantity). Use a single compute step to calculate the subtotal for each product, the overall total, the most expensive item, and the cheapest item. Use let bindings to keep the logic readable.
Next steps
- Expressions - Full expression language reference
- Decisions - When conditional logic needs more than ternary
- compute reference - Full specification