Coming from n8n or Zapier
Yes, there is a canvas. It sits at /canvas, lays out with dagre, has a node
palette, and generates each node’s inspector from that node kind’s schema, so
the fields you get are the fields the node actually takes. Expressions
autocomplete, validation runs as you type and marks the offending node, and
you can flip a graph between editing and watching a live run with the node
statuses overlaid on it.
This page maps your words onto ours and is straight about the canvas features we haven’t built.
Vocabulary
Section titled “Vocabulary”| Your word | Here | Worth knowing |
|---|---|---|
| node | node | http, shell, code, workflow, plus connector actions |
| connection | edge | edges carry order; data comes from expressions |
| credential | credential | resolved to auth headers at dispatch, never in the graph |
| execution | run | one entry in the run list, with a full timeline |
| execution history | run history | a retention window set by the deployment, not per-workflow; on a hosted org it comes with the plan |
| HTTP Request node | http node |
|
| Set / Edit Fields node | transform node |
a field table, or the JavaScript it compiles to - see Reshaping data |
| Code node | code node, or a transform |
code is a real script in bash, Python, TypeScript, Go or Rust, on an agent; a transform is one expression, in the engine |
| Webhook node | webhook trigger | owns an endpoint; a manifest verifies the delivery |
| Schedule trigger | schedule | cron or interval; each tick is a fresh run |
| Wait node | wait job or cryo sleep |
parks without holding a machine, for weeks if needed |
| sub-workflow | child run | the workflow: job kind, or a workflow node |
| Split In Batches / Loop Over Items | fan_out, or a graph that names itself |
see Repeating work |
| static / workflow data | state cell | state node, or cryo state; run-scoped or shared |
| error workflow | a run.failed handler |
a graph triggered by the event, like any other |
| expression | $expr |
{ "$expr": "nodes.fetch.output.status == 200" }, CEL |
| pinned data | pin | a step’s output, kept in your browser for editing the steps below it |
| Sort / Limit / Remove Duplicates / Merge | transform recipes |
named starting points, so you pick the operation rather than write it |
| Execute Node | run this node | runs that one step for real, on its own |
What you gain
Section titled “What you gain”Waiting is free and unbounded. A run parked on a timer, a signal or a bus event holds no machine. There is no execution-time ceiling to design around, so “wait seven days, then send the follow-up” is a line in the workflow rather than a scheduled job plus a database table you maintain yourself.
Steps are memoized, so retries don’t repeat work. A completed step’s
result is recorded, and a resumed run replays it instead of re-running it.
The dedup bookkeeping people hand-write around non-idempotent actions is the
engine’s job here. For dedup across separate runs - the same webhook
delivered twice, two schedules picking up one record - a state node with
op: add claims the key and tells you whether you were first. See
Durable state.
The canvas isn’t the only way in. The same workflow can be YAML in your repo or a script in your language, and a graph is a JSON definition you can read. A branching pipeline that has outgrown the canvas can move to code without leaving the product.
You can work against real data. Run one step on its own, pin what it
returned, and every step below it is edited against that - a transform
shows what each field produces as you type, with the fields the data
actually has offered as you write the expression. A pinned sample stays
in your browser rather than in the graph, because a graph gets published
and shared and the sample is a real response. See
Reshaping data.
Failures are events. A failed run emits run.failed on the project bus,
and a handler graph subscribed to it can notify, escalate or open a ticket.
Runs also carry a typed reason for why they are not progressing, so the run
page says what it is waiting for.
What we haven’t built
Section titled “What we haven’t built”- Partial execution. You can run a single node, and rerun a finished run from a chosen node, but you can’t run an arbitrary slice of a graph from the editor.
- Binary data. Files don’t flow between nodes yet. There is artifact
storage, reachable from a shell or script step with
cryo artifact put/get, but no node produces or consumes a file as a value. - A stuck-run watchdog. A run that fails tells you. A run that is quietly waiting on something that will never arrive doesn’t page you yet.
- Version listing, diff and rollback. Graphs are versioned and a stored version can be run by number, but the UI doesn’t list versions or diff two of them.
- A node marketplace. This one is deliberate. Connectors are data-only
manifests: a credential kind, some fields, and actions that lower to a
single HTTP request. Importing one can’t execute anything the author didn’t
declare.
matrix,slack,telegram,anthropicandopenai-compatibleship in the box, and anything else is anhttpnode, which is what a connector becomes anyway.
A first workflow
Section titled “A first workflow”The canvas has templates, but the shortest way to feel the difference is a script that waits:
cryo step welcome -- ./send-email.sh welcomecryo sleep 7dcryo step follow-up -- ./send-email.sh follow-upSubmit it with cryo submit onboarding.sh. The run parks for a week without
occupying anything, survives restarts and deploys, and shows up in the run
list the whole time with what it is waiting for. See the authoring
model for the handful of rules that apply once a workflow
gets longer than this.