Composites and sub-workflows

When a graph stops fitting on the screen, a piece of it can be folded into a single card — a composite. Inside it lies a full subgraph with its own nodes and edges; from the outside it is an ordinary node with the ports you assigned it. Composites are available on the free plan, like every other node.

Folding one, and looking inside

The composite is not in the palette — you cannot drag it in, it is only ever created out of a piece of graph you have already drawn.

  1. Select two or more nodes. A bar appears above the canvas with the number of selected nodes and a Merge button (that label is not localized); Ctrl+G does the same thing.
  2. The selected nodes disappear from the canvas and one composite card takes their place.
  3. Double-clicking it opens the body: the canvas switches to the subgraph and a Root › Composite trail appears at the top left. Clicking a link in the trail goes back up.
  4. The reverse is the Ungroup button above a selected composite, or Ctrl+Shift+G: the body’s nodes return to the canvas and their edges are restored.

Entry and Exit cannot be folded in — the attempt simply does nothing. That is deliberate: a workflow has exactly one entry point, and hiding it inside would produce a graph with no entry on the outside.

Interface ports

Inside the body, the boundary is marked by two service nodes: In and Out. The body must contain exactly one of each — otherwise validation reports composite.in_count or composite.out_count, and a composite with no body at all reports composite.no_subgraph.

A composite’s ports are not derived from the body automatically: they are a separate list you edit in the node’s settings, giving each port a label, a direction and a wire type. Folding fills that list in for you — from the edges that crossed the selection boundary: every edge coming in from outside becomes an input port, every edge leaving becomes an output, and the wire type is inherited from the original edge. That is why a folded piece of graph stays wired exactly as it was.

Entry
Request check
Exit
From the outside a composite is an ordinary node: it has as many ports as there were edges crossing the boundary.
In
LLM Response
Out
The body of that same composite: In hands out the input ports' values, Out collects the outputs.

The body is validated as a fragment, not as a workflow of its own: the “exactly one Entry” rule does not apply to it, and In serves as its entry point. Everything else — node types, wire compatibility, cycles — is checked by the same rules, and problems found inside surface on the outside with the composite’s name in front of the line.

Name isolation

The body executes in its own namespace of node outputs. In practice that means:

  • from the outside, {{ nodes.<a body node>.output }} does not work — the engine does not see the inner nodes; what comes out is only what the body placed on the output interface ports;
  • from the inside, the outer graph’s nodes are equally invisible: values arrive only through In;
  • identical identifiers are harmless: template_1 inside a composite and template_1 outside are different nodes. In the run report the inner ones are shown with a prefix: composite_1/template_1.

What is separated is specifically the node outputs. Session variables (the Set Variable node) are shared: what the body wrote is readable outside and the other way round — otherwise a composite could not accumulate state. The same principle is on the state and variables page.

Nesting, and its limit

A composite inside a composite is allowed: the body is an ordinary subgraph and may hold another composite. The depth is capped — 5 levels by default, and the value comes from the plan. The same counter counts WF tool calls and an agent acting as another agent’s tool: it is one shared recursion limit, not three separate ones. Exceeding it stops the node with a budget error — see timeouts and budgets.

Iteration shells (While Loop, For each, Map, Filter, WF tool), on the other hand, cannot be nested inside one another: the validator answers subgraph.nested_iteration_shell. The details and the ways around it are on the loops and iteration page.

A composite has no timeout of its own

The per-node time ceiling deliberately does not apply to a composite, to WF tool, or to an agent. Their own time is the sum of the times of the nodes they start, and each of those is already capped. A shared ceiling would mean the outer node fails on a timeout while the inner ones are honestly working, and the failure would arrive somewhere other than its cause. What bounds such a run is the whole run’s time ceiling and the ceilings of the individual body nodes.

WF tool: a subgraph as an agent’s tool

WF tool is the same “shell plus body” construction, except it is triggered by the model’s decision rather than by execution order. The node is attached to an agent’s extensions port over a link_extension wire, and you give it a name, a description and a JSON schema for its arguments; when the model decides to call the tool, the arguments arrive on the Data output (that starts the body), and whatever comes back into the Result input is handed to the model as the call’s result.

Entry
AI Agent
Exit
WF toolT
Tool body
  • Execute + Data
  • Extension
WF tool is a satellite of the agent: the purple link registers the tool, and the body runs when the model calls it.

The node has no execution input: as a step of the graph it never runs, and its body executes as many times as the model calls the tool — possibly zero. The name and the description are all the model has to go on when choosing, so “do the useful thing” is not what you call a tool. The fields and the constraints are on the WF tool node page; the whole picture on tools is in the agent’s tools.

A composite can also be attached to an agent over a link_extension wire, but that means something different: it does not become a tool itself — it hands the agent the tools and the memory that live inside its body.

Reusing across workflows

There is no node in Flow that calls another saved workflow. Composites and WF tool reuse a piece of graph inside one workflow. Between workflows there are three routes today:

  • copy the nodes — select, Ctrl+C, Ctrl+V in the other workflow; the composite’s body travels with its card, and a pasted Entry is attached to the existing one, so a second one never appears. The clipboard lives in the open tab: reloading the page loses it;
  • start from a template — the ready-made assemblies under templates;
  • call it over HTTP — deploy the second workflow behind a webhook and reach it with the HTTP Request node. The webhook is a paid trigger; the free plan only allows the public chat and the widget, see plan limits.

What next