Procedure
A Procedure is a named, callable sub-flow on the same canvas as your main workflow. You draw a Procedure once, and it becomes:
- A tool (named
proc_<name>) available to every Agent node in the workflow — no config, no wiring, no registration. - A callable available as
runSubFlow(name, input)from every Code node in the same workflow.
Procedures are how you factor a chatflow into reusable named pieces: instead of branching the main agent with deterministic if/then logic, you define a Procedure, describe what it does, and let the LLM decide when to call it.
How Procedures fit into a flow
A Procedure is literally a Start node with a custom name, sitting in a disconnected subgraph on your canvas. When you run the workflow, the Procedure doesn't execute as part of the top-level run — it only executes when an agent (or a code node) invokes it by name.
┌──────────┐ ┌─────────┐
│ ChatNode │──────▶│ Agent │ (main flow — user types, agent replies)
└──────────┘ └─────────┘
│
│ agent decides to call proc_lookup_order
▼
┌───────────────┐ ┌──────────┐ ┌─────────┐
│ lookup_order │────▶│ Fetch │────▶│ Response│ (procedure subgraph)
│ (Procedure) │ │ (Code) │ └─────────┘
└───────────────┘ └──────────┘
The procedure runs invisibly from the user's perspective — its result flows back to the agent as the tool-call result, and the agent weaves that into its reply.
Adding a Procedure to the canvas
- Open the Nodes sidebar.
- In the CONTROL group, drag the Proc item onto the canvas.
- The dropped node lands as a pill-shaped node labelled
procedure(orprocedure_2, etc. if you already have one). - Click the node to open its config panel. The Procedure section shows three fields:
Name (the node's displayed label)
Click the node's name label to rename it — e.g. lookup_order. This becomes the tool name the agent sees: proc_lookup_order.
- Allowed characters: letters, digits, underscores. Other characters get sanitized to
_. - Two procedures with the same name get a numeric suffix (
_2,_3) automatically.
Description
The text an LLM sees as the tool description. Make it imperative and specific about when to call the procedure:
"Look up an order by its ID. Use this when the user mentions an order number or wants to know an order's status."
Vague descriptions ("helper function") produce vague tool-calling behaviour — the LLM won't know when to use it.
Parameters Schema (JSON Schema)
Declares the fields the procedure expects. This becomes the tool's parameter schema the LLM sees:
{
"type": "object",
"properties": {
"orderId": { "type": "string", "description": "The order identifier" },
"includeItems": { "type": "boolean", "description": "Whether to include line items" }
},
"required": ["orderId"]
}
Leave this blank for a permissive default (agent passes arbitrary JSON). A typed schema produces much more reliable tool calls — the LLM fills in each required field.
Building the procedure body
After placing the Proc (Start) node, connect it to the nodes that do the work. The Start node forwards its caller's arguments as the input to the first downstream node, so a typical shape is:
[Proc: lookup_order] ──▶ [Code: fetch order] ──▶ [Response: formatted result]
- The Code node receives the procedure's input as its
inputvariable. If the caller passed{ orderId: "ABC123" }, theninput.orderIdinside the Code node is"ABC123". - The Response node is optional — if present, its value is what the procedure returns. If absent, the procedure returns the output of its last tail node.
Any Circuitry node works inside a procedure — Code, HTTP, Sheet, Chart, nested Agent, even another Procedure call. Guards on edges work normally.
Calling a Procedure from an Agent
You don't have to wire anything. When the agent turn starts, Circuitry scans the current workflow for every named Start node (every Procedure) and auto-registers each one as a tool in the agent's catalog under the name proc_<name>.
What the agent sees:
- Tool name:
proc_lookup_order - Description: whatever you typed in the Procedure's Description field
- Parameters: whatever schema you typed in the Parameters Schema field (or a permissive default)
The agent decides when to call it, the same way it would decide to call any other tool. Typed arguments flow into the procedure's Start node; the procedure's return value flows back as the tool result.
Requirements:
- The Procedure must have a custom name (not the default
Start). - The Agent node must have
useMCP: truein its config (already the default in driver-mode chatflows). - The workflow must contain the Procedure and the Agent in the same canvas.
When any of these are true, the procedure is automatically exposed — there is no separate registration step.
Calling a Procedure from a Code node
Every Code node has runSubFlow injected into its sandbox:
// Inside a Code node
const order = await runSubFlow('lookup_order', { orderId: 'ABC123' })
return { status: order.status, total: order.total }
- First argument is the procedure name (the Start node's displayed label — no
proc_prefix needed). - Second argument is the input payload; it becomes the procedure's Start-node input.
- Returns the procedure's output as a regular JavaScript value.
Available in JavaScript code nodes today. Python support is planned.
Visualising procedure execution
When an agent calls a procedure, you'll see in real time:
- The chat → agent edge pulses green (the agent is working).
- When the agent invokes the tool, the agent node border glows amber briefly.
- The procedure's Start → body edges light up green-traversed as the subgraph walks.
- Each body node gets an executing / completed badge.
- Hovering a body node shows its Node Output — the exact value that node produced.
When the user sends a new message, the previous turn's badges and traversal clear.
Example: an order-lookup procedure
Canvas setup:
ChatNode ──▶ Agent (main driver)
lookup_order (Proc) ──▶ Fetch (Code) ──▶ Response
Procedure config:
- Name:
lookup_order - Description: "Look up an order by its ID. Use when the user mentions an order number."
- Parameters Schema:
{
"type": "object",
"properties": {
"orderId": { "type": "string" }
},
"required": ["orderId"]
}
Fetch (Code) body:
const res = await fetch(`https://api.example.com/orders/${input.orderId}`)
return res.json()
Agent prompt:
"You help customers with order questions. Use
proc_lookup_orderwhen they ask about a specific order."
User says: "What's the status of order ABC123?"
The agent picks proc_lookup_order({ orderId: "ABC123" }), the procedure runs, the Fetch node returns JSON, the Response node returns it, and the agent formats a reply.
Tips
- One procedure, one job. A procedure that does "look up the order AND email the customer AND log to Slack" is hard for the LLM to reason about. Split into three procedures; let the agent orchestrate.
- Describe the when, not the how. The agent doesn't care how you implemented the procedure — it cares when to reach for it.
- Declare a typed schema. Without one, the LLM tends to pass empty args to avoid violating an opaque signature. Even a small
{ input: string }schema dramatically improves call reliability. - Keep procedures deterministic. Use an Agent inside a procedure only when you genuinely need LLM judgment in the procedure body; otherwise prefer Code + HTTP + conditions. Procedures shine when their execution is predictable.
Related
- Start Node — a Procedure is a Start with a custom name.
- Agent Node — agents auto-discover procedure tools.
- Code Node —
runSubFlowis available in every Code node.