Building Workflows

A workflow is a board of connected nodes. Data starts at the Start node and flows along the connections — each node takes the output of the node(s) before it, does one job, and passes its result on. You build the board visually, run it, and watch the data move through it.

This guide takes you from a two-node workflow to branching, loops, parallel execution, and running workflows remotely — with a worked example for each.

Your first workflow in 60 seconds

  1. Open Circuitry and create a workflow. A Start node is already on the canvas — that's your entry point.
  2. Drag an Agent node from the left sidebar onto the canvas.
  3. Drag from the bottom of the Start node to the top of the Agent node to connect them.
  4. Click the Start node and give it some test data in the right panel:
    { "topic": "the ocean" }
    
  5. Click the Agent node and set its prompt:
    Write a haiku about {{input.topic}}.
    
  6. Click Run (▶) in the toolbar. The nodes light up as they run, and the Agent's output appears on the node.

That {{input.topic}} is a template variable — at run time it's replaced with the value coming from the previous node. Templates are the glue that moves data between nodes.

For a fuller walkthrough, see Building Your First Workflow.

How data flows between nodes

Every node receives the output of the node(s) connected into it as its input, and produces an output that flows downstream. Data is passed as JSON.

You reach into that data with template variables, written with double curly braces:

TemplateWhat it gives you
{{input}}The complete output object from the previous node
{{input.fieldName}}One field from that output
{{input.user.name}}A nested field (dot-path access)
{{previousOutput}}Alias for {{input}}
{{__iteration.item}}The current item inside a Loop (see below)
{{env.API_KEY}}An environment variable (available in Code, Plugin and Database nodes)

A few things worth knowing:

  • Templates resolve at run time, not when you type them. The editor always shows the raw {{...}} text.
  • There are no filters or expressions{{input.x}} is a plain path lookup. If you need to transform a value (math, formatting, defaults), drop in a Code node first.
  • A path that doesn't exist resolves to an empty string, so a typo shows up as a missing value rather than an error.

See the full Template Variables reference for more.

Control flow

By default nodes run in sequence — each waits for the one before it:

Start → Fetch Data → Summarise → Save

Three node types let you change that: Condition (branch), Loop (repeat), and Fork/Join (run in parallel).

Branching with a Condition node

A Condition node sends the workflow down a true or false path based on its input.

Start → Condition ─ true ─→ Send VIP reply → End
                  └ false ─→ Send standard reply → End

Example — route by sentiment. Wire an Agent node that classifies a message, then a Condition that checks the result. The true branch handles angry customers, the false branch handles everyone else:

  • Agent node prompt: Reply only with "angry" or "ok": {{input.message}}
  • Condition: is the input equal to angry
  • True branch → an Agent that drafts an apology and escalates
  • False branch → an Agent that sends a normal reply

Repeating with a Loop node

A Loop node runs the nodes inside it once per item, and a Then node closes the loop and collects the results. The Loop figures out what to iterate over from its input:

  • a spreadsheet/datagrid → iterates the rows
  • a list of files → iterates the files
  • an array (e.g. input.reviews) → iterates the items
  • otherwise → a fixed number of times (default 3, capped at 100)

Inside the loop body, the current item is available as {{__iteration.item}}, along with {{__iteration.iteration}}, {{__iteration.total}}, {{__iteration.isFirst}} and {{__iteration.isLast}}.

Example — summarise every review.

Start → Loop ─→ Agent (summarise one) → Then → Agent (combine) → End
  • Start node test data:
    { "reviews": ["Great battery life", "Screen scratches easily", "Fast shipping"] }
    
  • Loop node: iterate over reviews
  • Agent node (inside the loop) prompt:
    Summarise this review in one short sentence: {{__iteration.item}}
    
  • Then node: closes the loop and hands the collected summaries on
  • Final Agent node prompt:
    Here are review summaries. Write a 2-sentence overall verdict:
    {{input}}
    

Running branches in parallel with Fork and Join

A Fork node splits execution into branches that run at the same time; a Join node waits for them all and merges their outputs. Use it when independent steps don't depend on each other:

          ┌→ Translate to French ─┐
Start → Fork → Translate to German → Join → End
          └→ Translate to Spanish ┘

Each branch runs concurrently, so three translations finish in about the time of one.

A complete example: triage incoming support tickets

This puts the pieces together — a loop, a branch, and AI in one workflow.

Start → Loop ─→ Agent (classify) → Condition ─ urgent ─→ Agent (escalate)
                                              └ normal ─→ Agent (auto-reply)
        → Then → End
  1. Start — test data: a list of tickets, e.g. { "tickets": [ { "from": "a@x.com", "body": "..." } ] }.
  2. Loop — iterate over tickets.
  3. Agent (classify)Reply with only "urgent" or "normal": {{__iteration.item.body}}.
  4. Condition — input equals urgent.
    • true → Agent (escalate) — drafts an alert and routes to the on-call queue.
    • false → Agent (auto-reply) — drafts a friendly response to {{__iteration.item.from}}.
  5. Then — closes the loop once every ticket is handled.

Run it in the editor to watch each ticket travel its own path, then — when you're happy — trigger the same workflow from a webhook so real tickets flow through it automatically (next section).

Running a workflow

There are two ways to run any workflow, and they use the same board:

In the editor

Click Run and watch it execute live:

  • Nodes are colour-coded by state (running, done, error) with spinners on active nodes.
  • Follow execution keeps the camera on the current node.
  • Hover a node to preview its input and output.
  • Set breakpoints to pause and inspect data — see Debugging Workflows.

This is how you build and test.

As a remote workflow (headless)

The same workflow can run with no editor open:

  • From a webhook — give the workflow a webhook trigger and any service (Stripe, GitHub, a form, a cron schedule) can fire it on demand. See Webhooks.
  • On a Circuitry Server — run it on a more powerful machine for native Python, GPU acceleration, and parallel execution spread across multiple servers. See Circuitry Server.

When a workflow runs headless, nodes that would normally pop a dialog (like a file-write confirmation) decide automatically instead of waiting for a click.

Handling errors mid-run

By default a failed node stops the run. Turn on Continue on error for an individual node (in its settings) to let the workflow carry on past it — handy for an HTTP call inside a loop where one bad item shouldn't abort the whole batch.

Reusing workflows

Don't rebuild the same logic twice:

  • Procedures — give a workflow's Start node a name and it becomes callable by that name, both from other flows and from chat agents as a tool. See the Procedure node.
  • Sub-workflows — the Workflow node runs another saved workflow as a single node inside the current one, so you can compose large automations out of smaller, tested pieces.

Canvas controls

ActionHow
PanDrag on empty canvas
ZoomMouse wheel or trackpad pinch
Multi-selectHold Shift and click nodes
DeleteSelect node(s) and press Delete
Add a nodeDrag from the sidebar, or press Space on the canvas

Workflows auto-save as you build; Ctrl/Cmd + S forces an immediate save. See all keyboard shortcuts.

Troubleshooting

  • A template comes out empty. The path doesn't match the actual data. Drop a Code node in and console.log(input) to see the real shape, then fix the path.
  • {{__iteration.item}} is empty. It only exists inside a Loop body — not before the Loop or after the Then.
  • A node won't run unless I disconnect an input. Make sure every node feeding it is itself connected back to the Start node; a dangling upstream node never completes.
  • A node runs twice or out of order. Check for duplicate connections and confirm your Loop has a matching Then to close it.

Next steps