Evaluates a small expression against the workflow's accumulated variables
and routes to either 'true' or 'false'. Use it to make routing decisions
that depend on prior node outputs without involving a script or an LLM.
Purpose#
condition is the cheapest, most deterministic branch in Roscoe. Reach for it
when you need to inspect numeric thresholds, compare strings, or combine
prior results with boolean logic: anywhere a programmer would reach for an
if.
YAML schema#
states:
passed-threshold:
type: condition # discriminator
label: Score above 80? # required, shown in UI / logs
expression: judge.score >= 80 # required, evaluated each run
on: # always 'true' / 'false'
'true': ship
'false': reviseConfiguration#
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
type |
'condition' |
yes | — | Discriminator. |
label |
string | yes | — | Human-readable name for the step. |
expression |
string | yes | — | Expression evaluated against variables. See expression reference. |
maxIterations |
integer (1-50) | no | — | Per-run iteration cap when this node sits in a feedback loop. See /docs/recipes/closed-loop-feedback. |
detectStall |
boolean | no | false |
Fail the run early if the expression produces an identical result three times in a row. |
on |
transition map | yes (in practice) | — | Should contain 'true' and 'false' keys. |
There is no validator: routing is fixed by the truthiness of the
expression's value.
Expression language#
Expressions are parsed by expr-eval,
not the JavaScript engine. The most important consequences:
- Equality is
==and!=, not===or!==. - Logic is
and/or/not(or&&/||/!). - No access to
process,require, or any Node.js globals. This is a sandbox.
Variables are referenced by node id and output key, e.g.
build.result == true or judge.score >= 80. See
/docs/authoring/expressions for the full
grammar.
Outputs#
| Key | Type | Notes |
|---|---|---|
result |
unknown | The raw value the expression evaluated to (often true/false, but expressions can return numbers/strings). |
Transitions#
condition always emits one of two transitions:
| Transition | When |
|---|---|
'true' |
The expression's value is truthy. |
'false' |
The expression's value is falsy (including 0, "", etc.) |
If the expression fails to parse or throws at runtime, the node fails with
the parser's error message. It does not silently route to 'false'.
Worked example#
name: gated-refund
version: 1
description: Only auto-approve a refund if it's within policy and the judge gave a high score.
initial: check-policy
states:
check-policy:
type: script
label: Check refund policy
script: |
const daysSincePurchase = 25;
export default daysSincePurchase <= 30;
validator:
kind: boolean
on:
'true': judge
'false': failed
judge:
type: ai_judge
label: Reviewer
model: claude-haiku-4-5
prompt: |
Rate how clear-cut this refund request is on a 0-100 scale.
validator:
kind: confidence
threshold: 70
on:
'true': gate
'false': failed
gate:
type: condition
label: Within policy AND high confidence?
expression: check-policy.result and judge.score >= 85
on:
'true': approve
'false': failed
approve:
type: script
label: Approve refund
script: |
console.log('Refund approved');
export default true;
validator:
kind: boolean
on:
'true': done
'false': failed
done:
type: end
label: Done
outcome: success
failed:
type: end
label: Failed
outcome: failureCommon pitfalls#
- Using
===or!==. These are JavaScript-only and will fail to parse inexpr-eval. Use==/!=. - Referencing a variable from a node that hasn't run. If the workflow
branched around the producing node,
judge.scorewill be undefined and the comparison will fail. Pair the condition with a prior node that guarantees the variable exists. - Truthiness surprises.
expression: somenode.stdoutis truthy for any non-empty string, including"false". When in doubt, compare explicitly:somenode.stdout == "ready". - Trying to call functions or access globals. The sandbox forbids it by design. Move that logic into a script node and route on its output.
Where to next#
- Conditional branching — a worked
recipe that routes by severity with
conditionnodes. - Expressions — the full expr-eval language you
can write in
expression. - Validators — how other node types produce the transition keys you branch on.