Every node is durably journaled. Once a node completes successfully, its output is recorded; the engine will never re-execute it during the same run, even if the service restarts. Nodes that talk to external systems (AI Agent, LLM, HTTP Request, Tool, document nodes) also support automatic retry on failure: configure max attempts and backoff in the Retry section of the node’s config drawer. See Reliability for the full guarantees.
Trigger
What it does. Every SuperFlow starts with exactly one Trigger node. It defines the shape of the input data the workflow accepts and decides how the workflow gets started. When to use it. Always. Your SuperFlow won’t run without one. Configure it once to declare your input fields, then choose how runs are initiated. Key parameters.- Trigger mode: choose Manual, Webhook, File Upload, or Schedule. See Triggers & schedules for the full guide.
- Webhook secret: used when the trigger mode is Webhook. External callers must include the matching secret in the
X-Webhook-Secretheader. - File Upload: when the mode is File Upload, the run always starts with
file_url,file_name,file_type, andfile_sizefields describing the uploaded file. Pair the Trigger with a Parse node to extract the file’s actual contents. See File upload trigger. - Schedule: when the mode is Schedule, a visual cron builder lets you pick frequency, time, and timezone.
{{ $('Trigger').json.customer_message }}.
A node runs only if it is connected, directly or through other nodes, to the Trigger. The editor marks any node that is not connected as unreachable, and that node does not execute.
AI Agent
What it does. Runs an existing Lyzr agent as a step in your SuperFlow. The full agent (its model, system prompt, tools, knowledge bases, memory) is reused exactly as configured in the Agents section of Studio. The node receives the upstream data, runs the agent’s reasoning/tool loop, and returns its response. When to use it. When you’ve already built (or want to build) a reusable agent in Studio and want to drop it into a workflow. Common use cases: classification, content generation, multi-tool task execution, customer reply drafting: anything where the same agent might be called from multiple workflows or directly. The AI Agent node runs a full agent, either one you already have or one you create from the node. If you want a single model call configured inline (system prompt, model, query, no tools), use the LLM node instead. Key parameters.- Use Agent selects the agent the node runs. Search for an existing agent, or select Create agent to build a new one in the agent builder and return to the flow with Create & use. Select Edit agent to change the selected agent, and Refresh to reload the agent list. Changes to an agent apply everywhere that agent is used. See Create an agent from the editor.
-
User Prompt (Query) is the input you send to the agent. This is usually an expression like
{{ $('Trigger').json.question }}. Leave it empty to use the input from the upstream node. -
Memory controls what the agent remembers when this node runs. It has four options:
- With No memory, the default, each run starts fresh.
- With Per execution, the agent keeps memory for the length of a single run.
- With Across executions, the agent keeps memory from one run of the flow to the next, so the flow can use what it has already seen to decide what to do next.
- With Custom key, memory is grouped by a value you supply in Memory Key, such as
={{ $json.customer_id }}. Nodes that share a key share the conversation. Custom key requires a saved workflow.
- Run as sub-agent: when this AI Agent node is connected downstream of an LLM node, enabling this turns it into a callable tool of the parent LLM, instead of running it as a separate DAG step.
LLM
What it does. Calls a model inline on the node: pick a provider/model, write a system prompt, supply a query, get a response. By default it’s a single, one-shot model call: no tools, no loop. But it can do more. If you connect downstream LLM, AI Agent, or Tool nodes and set Run as sub-agent on them, those downstream nodes become tools that this LLM can call. The LLM then runs in an agentic ReAct loop: reasoning, picking sub-agents/tools to call, getting their responses, and continuing, until it decides it’s done. This is how you build hierarchical agents (a planner LLM coordinating worker LLMs / agents / tools) without building a separate agent definition. When to use it. For pure text transformations: summarize, rewrite, classify, extract, or format. Or, when wired with sub-agent nodes downstream, as the brain of a multi-step, multi-tool workflow. The LLM node is the node to reach for when you want the agent loop but don’t want to bounce out to the Agents section to build a reusable agent first. Key parameters.- Provider / Model / Credentials: pick the model to call.
- System prompt: the instructions for the LLM, written directly on the node. Use the Generate with AI button to draft one from a description.
- Query: the user-side prompt, usually an expression pulling from upstream. Leave empty to auto-pick a message from common field names on the input (
message,query,input, etc.). - Temperature, Max tokens: standard generation controls.
- Memory controls what the model remembers when this node runs. It has the same four options as the AI Agent node: No memory, Per execution, Across executions, and Custom key.
- Run as sub-agent: flip this on when this LLM node is itself meant to be a tool of an upstream LLM node. When enabled, the node is skipped in the main DAG and runs only when the upstream LLM calls it.
Sub-agents and tool calls
LLM, AI Agent, and Tool nodes can be delegated to by an upstream LLM node. When a downstream node is marked as a sub-agent, it stops running as a normal DAG step and instead becomes a tool that the upstream LLM can choose to call during its reasoning loop. This is how you compose hierarchical agents (a planner coordinating workers) without writing a separate agent definition. Only the LLM node can act as the delegator. The AI Agent node runs its own internal reasoning loop using the underlying agent’s pre-configured tools, so it doesn’t pick up downstream sub-agent nodes. To build a hierarchy in SuperFlow, the head of the loop must be an LLM node.How to enable it
Connect the downstream node directly under an LLM node. The sub-agent toggle only appears when this structural condition is satisfied (a direct connection, or a one-hop connection through a Wait for Approval node; see below). On the downstream node, flip on the toggle in its configuration drawer:
The tool’s name shown to the parent LLM is
delegate_to_<NodeName> (or the tool’s action name for Tool nodes). When you give your sub-agent nodes clear names (“Researcher”, “Drafter”, “Refund Issuer”), the parent’s tool list reads naturally.
Describing the sub-agent to the parent LLM
When you flip the toggle on, additional fields appear that help the parent LLM decide when to call this sub-agent and what extra context to pass it:- Agent Description / Tool Description (AI Agent and Tool nodes): free-text description of what the sub-agent does. The parent LLM sees this alongside the tool name when deciding which tool to call. Write it like you’d write a function docstring: “Issue a refund for a customer order. Use when the customer message expresses dissatisfaction and references a specific order ID.” Clear, specific descriptions dramatically improve which-tool-to-call accuracy.
- Fixed Inputs (all three node types): a JSON object of extra context fields injected alongside whatever message the parent LLM generates. Useful for piping through identity context, environment flags, or any constants that the parent doesn’t need to reason about. Values support expressions, so you can pull from upstream nodes (for example,
{"user_id": "{{ $('Trigger').json.userId }}"}).
Purple edges on the canvas
Edges that feed a sub-agent node are drawn in purple instead of the default style. This is a visual cue that the connected downstream isn’t running as a normal DAG step: it’s a tool of the parent LLM. Edges fed into normal downstream nodes stay the default color, so a mixed graph (some sub-agents, some sequential next-steps from the same LLM) is easy to read at a glance.Approval gating before each delegation
You can place a Wait for Approval node between the upstream LLM and a sub-agent. When the LLM decides to call that sub-agent during its reasoning loop, the approval node fires first, pausing the loop, surfacing the request in the Approvals drawer, and resuming only when a human approves. This is the safest way to gate a sub-agent that has irreversible real-world side effects (a Tool that issues refunds, sends emails, mutates production data) while still letting the LLM choose when to invoke it.How the upstream LLM behaves
Once any downstream node is marked as a sub-agent, the upstream LLM stops being a single one-shot call and runs an agentic ReAct loop:- The LLM receives its prompt and the list of sub-agent tools available to it (each with its description).
- It reasons about which sub-agent (if any) to call, and with what arguments.
- The sub-agent runs. Its output becomes a tool result fed back to the parent LLM.
- The parent reasons again, calls more sub-agents if needed, and continues until it produces a final answer.
Nesting
Sub-agents can themselves have sub-agents. A “Planner” LLM can delegate to a “Researcher” LLM, which in turn delegates to a “Web Search” Tool node. Each level runs as its own ReAct loop. There’s no hard depth limit; keep it shallow enough that you can reason about it.When to reach for it
- Multi-agent orchestration: a planner deciding which specialist agent to call for each request.
- Conditional tool use: letting the model decide whether a tool is needed, instead of always calling it.
- Multi-step research/drafting: research → critique → revise, with the model in control of the loop.
- Gated sub-agents: combining sub-agent delegation with Wait for Approval for safety on irreversible actions.
- Anywhere you’d otherwise write a custom agent with tools: but you’d rather configure the pieces visually.
HTTP Request
What it does. Makes an HTTP call to any URL and returns the response. The bridge between your SuperFlow and the outside world. When to use it. Calling a third-party API, posting to a webhook, hitting your own backend, uploading or downloading files, fetching data to feed into a downstream agent. Key parameters.- Method: GET, POST, PUT, PATCH, DELETE.
- URL: the endpoint. Expressions are supported, so you can build URLs from upstream data (
https://api.example.com/users/{{ $json.user_id }}). - Authentication: pick a scheme and the node signs the request automatically. See Authentication below.
- Headers: key/value pairs. Common ones:
Content-Type, custom app-specific headers. Auth headers are set by the chosen scheme, so you usually won’t setAuthorizationby hand. - Query parameters: key/value pairs appended to the URL.
- Body: JSON, form, multipart, or raw text. Expression-aware, so any field can be templated from upstream nodes. To send a file as the body or as a multipart field, reference an upstream file item directly.
- Response Format: Auto (parse JSON when the response is JSON, otherwise text), Raw text (always return as text), or Binary blob (wrap the body as a file item, for downloading PDFs, images, signed URLs returning binary, etc.).
HTTP authentication
The HTTP Request node ships with built-in authentication for the patterns real production APIs use. Pick a scheme in the Authentication section of the node config and fill in the credentials, with no Function-node workaround and no signing code to maintain.
Combine any scheme with the rest of the HTTP node config. Auth runs before the request is sent, and the body/headers/expressions you configured still apply.
Working with files
Files (PDFs, images, signed documents, anything binary) flow through a SuperFlow as first-class items, the same way numbers and strings do. There’s no separate “binary channel” or conversion step between nodes. Any node that needs to read a file can reference it directly; any node that produces a file emits it as a regular workflow item. A file item carries the contents, filename, content type, and size:$blob marker tells the engine “this isn’t a normal JSON object, it’s a wrapped file.” You generally don’t see it directly; you reference the field that contains it ({{ $('Parse').json.file }}) and the engine handles the unwrapping when the next node needs the raw bytes.
Where files come into a SuperFlow
- Trigger node: set the trigger mode to File Upload for a dedicated file-in entry point (every run receives
file_url,file_name,file_type, andfile_size). For Manual or Webhook triggers that expect a file field, the editor’s Upload & Run button accepts a drag-and-drop file, and webhook callers can supply a file URL orasset_idin the trigger payload. Either way, add a Parse node right after the Trigger to turn the uploaded file into usable text. - HTTP Request node: set Response Format to Binary blob to wrap a binary response body as a file item with the response’s filename and content type. Use this for downloading PDFs, images, signed URLs that return binary, etc.
- Wait for Approval form: an approver can attach a file via a typed file field on the approval form (see Wait for Approval). The uploaded file lands on the resumed run as a file item.
Where files go
- HTTP Request node: reference a file item in the request body and the node streams the raw bytes on the wire (not base64). Works for direct PUT/POST uploads, multipart form fields, and signed-URL uploads.
- Document nodes (Parse, Extraction, Label): accept either a file URL string or an upstream file item. No conversion node needed in between.
- Display in the editor: file items render as downloadable previews in the per-node output drawer and the execution panel (filename + content type + Download button).
Size limit
A single file can be up to 100 MB. Files larger than this should be uploaded directly to your storage (S3, GCS, Azure Blob) and referenced by URL, typically via a Code or HTTP Request node that generates a signed URL.Error edges
Most nodes that call an external system have retries. But what should happen when retries are exhausted and the node fails permanently? Two paths, picked per node. Default. If you don’t configure anything, a permanent failure of any node fails the entire run. The failed step shows up in History with its error message preserved for diagnosis. This is the right default for steps that must succeed for the workflow to make sense: a critical database write, an LLM call that produces the final answer. Opt-in error edges. For steps where partial failure is acceptable (or where you want to escalate failures to a human), open the node’s settings drawer and enable Handle errors. A second output handle appears on the node, coloured red, for the error path. When the node fails permanently:- The error output fires with an item containing the error message, error code, and the original input.
- Whatever you wire to the error output runs as normal: a fallback HTTP call, an escalation to a Wait for Approval node, a notification to Slack or email.
- The rest of the workflow continues; the run as a whole doesn’t error out.
When to reach for error edges
- Fallback paths. Try one API; fall back to another on failure. “If the primary payment processor is down, route to the backup.”
- Human escalation. Pipe failures into a Wait for Approval so an operator can take over manually when the automation can’t recover. Combines well with HITL forms, where the operator sees the failure context and decides what to do.
- Per-iteration recovery inside a Loop. Let one bad row of input fail without killing the rest of the batch: the failed iteration’s error flows out, the rest of the iterations continue.
How it composes
Error edges work with retries, not against them. The error output fires after retries are exhausted, not on the first failure. So configure retries for transient flakiness (network blips, rate limits) and error edges for permanent failures you want to recover from gracefully. The two together give you a graceful-degradation pattern at the visual layer, no try/catch code to maintain. Existing workflows without the toggle behave exactly as before; error edges are strictly opt-in.Code
What it does. Runs JavaScript inline. The Code node opens a Monaco editor in the config drawer (with an Expand button for a full-screen editor) where you can write arbitrary JS to transform data, do math, run regex, or anything else that’s awkward to express with the visual nodes. When to use it. Quick data shaping that no other node does cleanly: combining fields, generating IDs, custom date formatting, filtering with custom logic, etc. Key parameters.- Code: the JavaScript. The following globals are available:
$input.all(): the full list of input items$input.first(): the first input item$json: the first input item’sjsonpayload (shorthand)$items: alias for the full list
- Timeout: code is sandboxed and capped at 10 seconds.
If / Else
What it does. Binary conditional branch. Evaluates a condition on the input data and routes the items to one of two outputs: true (output 0) or false (output 1). When to use it. Splitting flow based on a value, for example “is the customer priority urgent?”, “did the LLM say yes or no?”, or “is the response longer than 200 characters?”. Two modes.- Rule mode (default): a visual condition builder. Each row is left operand · operator · right operand. Both operands can be literals or expressions, and multiple rows are joined with AND / OR. Best for deterministic checks: numeric comparisons, exact string matches, field presence.
- AI mode: write the condition as a natural-language statement (for example, “the customer message expresses frustration” or “the document mentions a refund request”). An LLM evaluates the statement against the upstream data and returns true or false. Best for fuzzy, judgment-call routing that’s awkward to express as a strict rule.
- Mode: Rule or AI.
- Conditions (Rule mode): rows of left · operator · right. Combine with AND / OR when there’s more than one.
- Condition statement (AI mode): the natural-language condition for the LLM to evaluate. Use expressions to include upstream context (for example,
Is "{{ $json.message }}" expressing frustration?).
Set
What it does. Reshapes the data. You define key/value pairs, and the Set node emits items with those fields populated. When to use it. Renaming fields, adding constants, building a clean payload for the next node, “stamping” a record with metadata before saving it. Key parameters.- Assignments: a list of
key = valuerows. The value can be a literal, a field reference (use the picker), or any expression.
Loop
What it does. Iterates over the input items. For every item (or every batch of items), the body of the loop runs once and its outputs accumulate. When to use it. Processing a list, for example looping over rows from an HTTP response and running an agent on each, or batching 100 emails into groups of 10 for an external API. Key parameters.- Mode: each (run the body once per input item) or batches (group input items into chunks).
- Batch size: when mode is batches, how many items per group.
- Loop body: the nodes between the Loop node and its loop-back edge form the body. Each iteration runs the entire body before moving to the next item or batch.
Wait for Approval
What it does. Pauses the SuperFlow and asks a human to approve or reject before continuing, optionally with a typed form for the approver to fill in. The run stays paused (durably; restarts won’t lose it) until someone responds. When to use it. Anywhere you want a safety gate: before sending an email an LLM drafted, before charging a customer, before deleting records, before publishing content. Reach for a form on top of the basic approve/reject when the approver needs to supply extra context (notes, a category, a signed document) that the rest of the workflow depends on. Key parameters.- Approval message: what the approver sees. Markdown is supported, and expressions are encouraged so the message can show upstream context. For example:
Please review the proposed reply to {{ $json.customer_email }}: {{ $json.draft_reply }}. - Form schema: an optional list of typed fields the approver fills in alongside the decision. See Approval forms below.
- Notification emails: optional list of email addresses to ping when the approval pauses. The email links to the approval detail page.
- Output 0 (approved): items continue down this path when a human approves. The input items flow through, merged with any form values the approver submitted.
- Output 1 (rejected): items continue down this path when a human rejects, also merged with any form values submitted (plus a
rejection_reasonalias).
Approval forms
Open the Form schema editor on the Wait for Approval node to add fields the approver will fill in. Each field has:
The Required on dropdown is what lets you say “reviewer notes are mandatory if you reject, but optional if you approve”, or the reverse. Boolean fields skip the Required check (they always have a value).
When the workflow pauses, the approver sees the message + the form. Submitting either decision validates the required fields for that decision, then merges the submitted values into the items flowing through the corresponding output. The same validation runs server-side, so direct API submissions can’t bypass it.
File fields specifically: when an approver uploads a file, it becomes a file item in the merged output. The next node downstream can send it to an HTTP endpoint, parse it, or display it as a download, same as any file produced anywhere else in the workflow.
A typical pattern:
- Wait for Approval node with a form:
reviewer_notes(text, required on reject),category(dropdown: expense / capex / refund, required on approve),signed_approval(file, required on approve). - The approve path connects to an HTTP Request that posts the original record + the form fields + the uploaded file to your system of record.
- The reject path connects to an HTTP Request (or email node) that records the rejection with the reviewer’s notes.
Execute Workflow
What it does. Calls another SuperFlow as a single step. The sub-workflow runs to completion, and its final output is emitted as this node’s output. When to use it. Reuse: extract a common sub-flow (a “send notification” pipeline, a “validate customer” pipeline) into its own SuperFlow and call it from many parents. Key parameters.- Source: either pick an existing SuperFlow from the dropdown (recommended) or paste an inline workflow JSON.
- Input: the data passed to the sub-workflow’s Trigger node.
Knowledge Base
What it does. The Knowledge Base node works with a Knowledge Base at any step in a flow. It has two operations: Retrieve searches a Knowledge Base for relevant chunks, and Train adds text to a Knowledge Base. You find the node under AI in the node library. When to use it. Use Retrieve when a step in the middle of a flow needs grounded information from your own documents, for example to look up the relevant policy before an LLM node drafts a reply. Follow it with a Rank node when you want the best passages first. Use Train to load content into a Knowledge Base as part of a flow, for example after a Parse node extracts text from an uploaded file. Key parameters. Every Knowledge Base node has three settings:- Knowledge Base selects the Knowledge Base the node works with. Search for an existing one, or select Create knowledge base to make a new one. Select Refresh to reload the list.
- Operation is Retrieve or Train.
- Timeout (seconds) is how long the node waits for the operation to finish. The default is 120.
- Query is the text to search for. Leave it blank to use the query from the upstream node, or use the field reference picker to point it at a specific field.
- Top K is the number of chunks to return. The default is 10.
- Retrieval type sets how chunks are matched. The options include Basic (pure similarity search), MMR (relevance plus diversity), and HyDE (hypothetical document embeddings). See Retrieval types for when to use each one.
- Score threshold filters out chunks whose similarity score falls below this value. The default is 0, which keeps every chunk.
- Metadata filters is an optional list of filters, and the node only searches chunks whose metadata matches them. The most common filter uses the
sourcefield to limit retrieval to specific documents. Select + Add filter to add one, or open Advanced: raw filter JSON to write the filter as JSON.
- Text is optional. Leave it blank to train on the
chunksorfull_textfrom the upstream node, such as the output of a Parse node. - Source is an optional name for where the text came from, for example
report.pdf. Retrieval can filter on it later with asourcemetadata filter. - Chunk Size is the size of each chunk the text is split into. The default is 1000.
- Chunk Overlap is how much adjacent chunks share, which preserves context at chunk boundaries. The default is 100.
Decide
What it does. The Decide node asks a decision model one or more typed questions about each incoming item and writes the answers onto that item. It uses Jev, the decision model from Typesafe AI, which returns calibrated answers rather than free text. Decide does not branch on its own: it has a single output, and you route on its answers downstream with an If / Else or Switch node. When to use it. Use it for classification and triage where you want a number you can set a threshold on, rather than free text. Typical questions are which queue owns a ticket, how urgent it is, or whether a message is spam. Put every question you have about an item on one Decide node. All of a node’s questions go to the model in a single request, so adding a question costs tokens but not another round trip. Key parameters.- State is what the questions are about. Leave it empty to evaluate the whole incoming item, which lets a question refer to one of the item’s fields by name. Set it to an expression, string, object, or array when the item carries a lot of data the questions do not need, because accuracy drops as irrelevant state grows.
- Questions is the list of questions. Add each one with + Add question. The node needs at least one question to run.
- Timeout (seconds) is how long the node waits for the model on each item. The default is 30.
- Name is the field the answer is written to. It must be a valid identifier (letters, digits, and underscores, not starting with a digit) so that downstream expressions can read it as
$json.<name>. Names must be unique on the node. - Type is
choice,score, orprobability. - Instructions are the question itself. State the exact condition, because the model reads it literally.
- Criteria depend on the type, as the table below shows.
A probability is the answer and the certainty at once: 0.05 is a confident no, 0.95 is a confident yes, and 0.5 is genuine doubt. Branch on it with a threshold, such as
{{ $json.is_spam > 0.8 }}, and use a band around 0.5 when you want a separate lane for unsure cases. Only choice and score questions get a _confidence field, because a probability already expresses its own certainty.
For a score, branch on <name>_level rather than <name>. The levels are the outcomes you wrote, and the decimal between them is only an interpolation.
Output. Decide has one output. Every incoming item passes through with the answer fields above added, plus three more fields:
answersholds the full reply to each question, keyed by question name. Use it when you want the whole distribution rather than only the winner.decide_modelis the version of the decision model that answered.decide_usageholds{"input_tokens": N, "output_tokens": N}for this item’s call.
answers field for three questions:
choice answer carries choice, confidence, and probabilities, with one probability per option. A score answer carries score, confidence, and legend, which maps each level index to its description. A probability answer appears in answers under the model’s own name for the type, noul, with the probability in the noul field.
Example. The following questions triage a support ticket:
{{ $json.route }} picks the queue, and an If / Else on {{ $json.urgency_level >= 2 }} pages someone.
Things to know.
- The node runs once per incoming item, so a list of 50 items makes 50 calls.
- The decision model is not a calculator and does not read dates as ordered quantities. Do arithmetic and date comparisons in a Code node, then ask the question about the result.
- With no upstream items, the node still runs once against the State parameter. This means a Decide node wired directly to a Trigger with a literal state works.
Rank
What it does. The Rank node puts every incoming item in front of the decision model at once and reorders the items by how well each one answers the query. It makes one call for the whole set. Rank uses Jev, the same decision model as Decide. The difference is shape: Decide asks about each item separately, and Rank asks once about all of them. When to use it. Use it to rerank a shortlist, such as the passages a Knowledge Base node retrieved, candidate replies, or search results. Rank is a reranker, not a search engine, so build the shortlist first with retrieval or a Limit node. Key parameters.- Query is what to rank against, such as the question, the brief, or the task. Expressions are allowed, for example
{{ $('Trigger').json.chatInput }}. - Instructions describe how to judge a candidate against the query, for example “Which passage best answers the question?” This field is required.
- Candidate fields are the top-level fields of each item that the model compares, such as
titleandtext. Add each one with + Add field. Only those fields are sent, and a field that is missing on an item is skipped. Leave the list empty to send every field. Narrowing the fields keeps more candidates inside the token budget and removes distractors. - Limit keeps only this many of the best candidates. Leave it empty to keep all of them, reordered.
- Validation question is an optional yes or no question asked once about the whole set, for example “Does any of these actually answer the question?” A ranking is relative, so something always comes first even when nothing fits. The validation question is how you detect that none of the candidates fit.
- Timeout (seconds) is how long the node waits for the model. The default is 30.
rankis the item’s position, starting at 1.rank_scoreis the model’s probability that this candidate is the best answer. The scores across the set add up to 1.rank_confidenceshows how clearly the top candidate separated from the rest. It describes the whole set, so every item has the same value.validation_probabilityis the probability that the answer to the validation question is yes. It appears only when you set a validation question, and every item has the same value. Branch on it with an If / Else node, for example{{ $json.validation_probability < 0.3 }}to catch the case where nothing fits.rank_modelis the version of the decision model that answered.
- A run can rank at most 255 candidates. More than that fails the node, so shortlist upstream.
- Tied items keep their incoming order.
- With no incoming items, the node emits nothing and does not call the model.
Loop Until
What it does. The Loop Until node re-runs a region of the canvas until a condition holds or a budget is spent. The Loop node iterates over items, while Loop Until iterates on a result: it generates, judges, and tries again until the judge is satisfied. When to use it. Use it for draft-and-critique loops, retrying until an output is valid, and best-of-N generation that stops early once a result is good enough. Set up the loop. Loop Until has three outputs, and the Continue output defines the loop. Drag the blue Continue dot on top of the Loop Until node onto an earlier node. That back-edge sets the loop region, which runs from that node down to the Loop Until node on every iteration. The canvas shows the region as a dashed arc over its nodes. Continue carries no data: each iteration starts the region’s first node again with the same items that entered the loop from outside. Without a Continue edge, the node fails at run time. Key parameters.- Exit Condition is an expression evaluated after each iteration. When it is true, the loop exits through Done. It must resolve to a boolean, for example
={{ $('Judge').json.verdict === 'approved' }}rather than={{ $('Judge').json.verdict }}, because a non-boolean string counts as false and keeps the loop running. Leave it empty to loop until a budget runs out. - Max Iterations is the iteration budget. The default is 10.
- Max Tokens is a token budget, summed over the AI Agent, LLM, Task Decomposition, and A2A Agent nodes in the region, plus tokens from any loop nested inside it. Leave it empty for no limit. A value of 0 is reported as invalid.
- Score Expression is an optional expression that yields a number for each iteration, for example
={{ $('Evaluator').json.score }}. A numeric string such as"8"is accepted. Setting it turns on best-of-N tracking: when the loop exits because a budget ran out, it emits the items from the best-scoring iteration instead of the last one. - Stop if no improvement ends the loop after this many consecutive iterations without a better score. It requires a score expression.
- Done (output 0) fires when the condition holds. It carries the items that reached the Loop Until node on that iteration.
- Continue (output 1) is the back-edge. It carries no data.
- Exhausted (output 2) fires when a budget stops the loop. It carries the best-scoring iteration’s items when a score expression is set, and the last iteration’s items otherwise. If you leave Exhausted unconnected, these items leave through Done instead.
_loop object:
The
exit_reason field takes one of five values:
Loop variables. Nodes inside the region can read the live state of the loop through
$loop:
The two numbering schemes differ:
$loop.iteration starts at 0, while _loop.iterations, best_iteration, and $loop.bestIteration count from 1. Outside a loop, $loop is null.
Things to know.
- The exit condition and score expression are evaluated fresh on every iteration, against that iteration’s items.
- A branch that is not taken inside the region, such as the unused side of an If / Else node, produces no items on that pass. Nothing from an earlier pass carries over.
- A node that fails anywhere in the region fails the loop, and with it the run. Per-node retry settings and error edges do not apply inside a Loop Until region.
App tools
What it does. An app tool node runs one action in an app, such as sending an email, posting a Slack message, or creating a Google Doc, without an agent or an LLM in the loop. Each app is its own node under Apps in the node library, for example Gmail, Slack, Google Docs, Google Calendar, SharePoint, Microsoft Outlook, Notion, and Apollo. Some apps are offered through more than one integration provider and appear once for each, such as Gmail (ACI) and Gmail (Composio). Custom tool calls one of your own tools. When to use it. Use an app tool when a step should always do the same thing in an app, with inputs that come from earlier steps. When a model should decide whether and how to call the tool, turn on Run as sub-agent and connect the node downstream of an LLM node. See Sub-agents and tool calls. Connect an account. Open the node to see which account it uses. When the app is connected, the node shows Connected as followed by the account. Select Connect another account to sign in with a different account. A step runs with your own connected account for that app. If you have not connected the app, the step fails with a message asking you to connect your account. A step can instead be pinned to the account of the person who set it up, so every run uses that account. Only that person can create or change a pinned step, and a pinned step that has been edited since its last save fails until you save it and run again. Key parameters.- Action is the operation to run. Search the app’s actions and select one, for example from the 32 actions Google Docs offers. The node then shows the inputs that action needs.
- The node runs once for each incoming item, and expressions in its inputs are resolved against each item in turn.
- The tool’s result arrives as data fields, so downstream nodes can read them with expressions.
- When the app reports a failure inside an otherwise successful response, such as an authentication error, the node fails, so its retry settings and error edge apply.
Quick reference table
The remaining nodes, useful but typically less central to a first SuperFlow. Each is one drag away from the same node palette.
For details on any node, hover its entry in the palette in the editor. Every node ships with inline parameter descriptions next to each field.