Skip to content

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