Skip to content

Decisions

The decide step evaluates conditions and routes execution accordingly. Use it when your machine needs to take different paths based on data. Each branch decision is recorded in the behavioral ledger, making your control flow auditable after the fact.

Basic syntax

decide <name>
when <condition>
<expression or steps>
when <condition>
<expression or steps>
otherwise
<expression or steps>

Conditions are evaluated top to bottom. The first when that matches executes. If nothing matches, otherwise runs. If there is no otherwise and nothing matches, the step returns null.

Simple branching

machine ticket_router
accepts
priority as text, is required
responds with
queue as text
sla_hours as number
implements
decide route
when input.priority == "urgent"
{queue: "critical", sla_hours: 1}
when input.priority == "high"
{queue: "priority", sla_hours: 4}
when input.priority == "medium"
{queue: "standard", sla_hours: 24}
otherwise
{queue: "backlog", sla_hours: 72}

Natural language conditions

decide supports both symbolic and natural-language operators. These are equivalent:

// Symbolic
when input.amount > 10000
when steps.score.value != "pass"
when input.count >= 5 && input.active
// Natural language
when input.amount is greater than 10000
when steps.score.value is not "pass"
when input.count is at least 5 and input.active
SymbolicNatural language
==is
!=is not
>is greater than
<is less than
>=is at least
<=is at most
&&and
||or

Branching on step results

The most common pattern: use the output of an ask step to decide what happens next.

machine approval_workflow
accepts
amount as number, is required
department as text, is required
responds with
approved as boolean
approver as text
ensures
permissions
allowed to
llm_call
implements
ask evaluate, using: "anthropic:claude-haiku-4-5"
with task "Evaluate this expense. Amount: ${input.amount}, Department: ${input.department}. Return risk level."
returns
risk_level as text
assuming
risk_level: "low"
decide route_approval
when input.amount is greater than 10000
{approved: false, approver: "CFO review required"}
when steps.evaluate.risk_level is "high"
{approved: false, approver: "Risk committee"}
when input.amount is at most 500
{approved: true, approver: "auto-approved"}
otherwise
{approved: true, approver: "manager"}

Branching to named flows

For branches that need multiple steps, dispatch to a named flow with run flow(name):

machine order_processor
implements
compute check_inventory
{in_stock: input.quantity <= 100}
decide fulfillment_path
when check_inventory.in_stock
run flow(ship_direct)
otherwise
run flow(backorder)
flows
flow ship_direct
ask create_shipment, from: "@mashin/actions/shipping/create"
items: input.items
compute result
{status: "shipped"}
flow backorder
ask notify, from: "@mashin/actions/notifications/send"
message: "Backorder needed"
compute result
{status: "backordered"}

decide vs. compute ternary

For simple value selection, a ternary in compute is shorter:

// Simple: use ternary
compute label
{tier: input.amount > 1000 ? "premium" : "standard"}
// Complex: use decide
decide route
when input.amount > 10000
{tier: "enterprise", handler: "account_manager"}
when input.amount > 1000
{tier: "premium", handler: "priority_support"}
otherwise
{tier: "standard", handler: "general_support"}

Use decide when: there are more than two branches, each branch needs multiple fields, or you want branches visible in the ledger trace. Use ternary when: it is a simple two-way value choice on a single field.

Governance

Decide steps are pure control flow. They do not require permissions and do not make external calls. However, every branch decision is recorded in the behavioral ledger with the condition that was evaluated and which branch was taken. This makes control flow auditable.

Steps inside branches inherit normal governance. An ask step inside a when clause still requires llm_call permission.

Try it

Build a machine that takes a customer order with amount, customer_tier, and item_count. Use a decide step to route: VIP customers with large orders get express handling, small orders get auto-processing, and everything else goes to standard review.

Next steps