Workflow Node Reference
Reference for all workflow node types, configuration fields, I/O specifications, SSRF protections, and validation rules
The Clouisle workflow engine supports native complex objects, streaming inference, conditional routing, and loop/iteration containers. Workflow definitions use schema_version: 2, where graph structures consist of nodes and edges (built on React Flow).
Node Categories & Catalog
The current canvas picker offers 19 addable node types (normalCategories: 2 model + 6 logic + 6 transform + 5 extension). Inside an iteration/loop container the picker switches to a container-only catalog (swapping iteration_exit/loop_exit in for iteration/loop/pause). The backend executor registry additionally holds 25 executable node types, including internal entry nodes such as user_input, trigger, iteration_start, and loop_start. The canvas also retains frontend aliases or visual markers such as start, iteration_exit, loop_exit, and comment; not all map to independent executors. The table lists regular nodes, runtime nodes, and visual helper markers together:
| Category | Type Identifier (type) | Label | Primary Purpose |
|---|---|---|---|
| Model | llm | LLM | Invoke large language models for text generation and reasoning |
media_generation | Media Generation | Call team-authorized image or video generation models | |
| Logic | condition | Condition Branch | Multi-branch IF/ELSE routing logic |
question_classifier | Question Classifier | Classify user intent dynamically using LLMs | |
decision | Decision | Ask a decision model a typed question and branch on the answer | |
iteration | Iteration Container | Iterate over array variables sequentially | |
loop | Loop Container | Execute child nodes repeatedly until conditions are met or maximum count is reached | |
pause | Pause | Suspend workflow execution pending human approval or variable inputs | |
| Transform | code | Code Execution | Execute Python or JavaScript snippets in a secure sandbox |
template | Template Transform | Format and assemble text using Jinja2 templates | |
file_to_url | File to URL | Convert temporary file/image variables to persistent access URLs | |
variable_aggregator | Variable Aggregator | Aggregate dispersed variables into an object, array, or concatenated text | |
variable_assignment | Variable Assignment | Assign or update conversation context variables | |
parameter_extractor | Parameter Extractor | Extract structured arguments via LLM, Regex, or JSON Path | |
| Extension | sub_workflow | Sub-workflow | Invoke other published workflows within the workspace |
agent | Agent | Call a published Agent for autonomous goal execution | |
tool | Tool | Invoke built-in tools, custom HTTP tools, or MCP services | |
knowledge_retrieval | Knowledge Retrieval | Search a bound knowledge base and retrieve chunk contexts | |
answer | Output | Assemble final results and support streaming output to clients | |
| Executor-level (not in the canvas picker) | http_request | HTTP Request | Perform external HTTP/HTTPS API calls (restricted by SSRF policies) |
document_extractor | Document Extractor | Extract plain text or Markdown from uploaded PDF/DOCX files | |
| Entry & Lifecycle | user_input | Start | Define human-initiated input parameters and system variables (frontend canvas alias start) |
trigger | Trigger | Webhook, scheduled cron, or event-driven entry points | |
iteration_start / loop_start | Container Start | Internal virtual entry executor node passing parent container context | |
iteration_exit / loop_exit | Container Exit | Internal visual exit marker on the canvas (no backend executor; child nodes are orchestrated by parentId) | |
comment | Comment | Static canvas sticker, ignored during runtime execution |
Picker nodes vs executors
http_request and document_extractor have independent backend executors (callable by the API or by imported packages) but do not appear in the canvas picker, so they cannot be dragged in from the UI. Conversely, iteration_exit/loop_exit are only container exit markers on the canvas with no dedicated executor; the container schedules child nodes by parentId at runtime.
Detailed Node Configuration Reference
1. LLM Node (llm)
Configuration container: node.data.llmConfig or node.data.config.
| Field | Type | Default | Description & Constraints |
|---|---|---|---|
modelId | UUID string | Required | Team-authorized chat model ID (team_models.id) |
systemPrompt | string | "" | System prompt supporting {{node.var}} template variables |
userPrompt | string | "" | User prompt supporting template variable interpolation |
temperature | float | 0.7 | Sampling temperature passed to the model |
maxTokens | int | 2048 | Maximum generated token count passed to the model |
topP | float | 1.0 | Nucleus sampling threshold passed to the model |
streaming | bool | false | Enable token streaming; downstream Output nodes can relay streams directly |
responseFormat | string | "text" | Output format: "text", "json" (json_object), or "json_schema" |
jsonSchema | string (JSON) | null | Strict JSON schema definition required when format is json_schema |
inputs | array | [] | Parameter mapping list bound to this node |
Outputs:
response(string): Generated response text (a lazy streaming proxy when streaming is true)reasoning(string): Chain-of-thought reasoning process (e.g., DeepSeek R1 reasoning trace)usage(object): Token metrics includingprompt_tokens,completion_tokens, andtotal_tokens
2. Decision Node (decision)
The Decision node hands one state to a decision model (model_type: decision, currently TypeSafe AI) and picks a branch from the returned typed answer. Unlike the LLM node, a decision model generates no prose — it returns only a typed answer plus a probability distribution, and the node maps that answer onto output handles.
Configuration container: node.data.decisionConfig (with node.data.config retained for legacy definitions).
| Field | Type | Default | Description & Constraints |
|---|---|---|---|
modelId | UUID string | Required | Team-authorized decision model ID; the picker lists only enabled models with model_type: decision |
stateTemplate | string | Required (legacy alias inputVariable) | State handed to the model; supports {{variables}} and must resolve to a string |
questionId | string | "decision" | Question key used to read the answer back from the response (answers[questionId]) |
questionType | string | "choice" | Question type: choice, score, or noul (yes/no probability) |
instructions | string | Required | The judgement you ask the model to make |
options | string[] | Frontend default ["yes","no"] | choice: 1–255 unique non-empty options; score: 2–10 unique non-empty ordered levels |
defaultHandle | string | "default" | Branch handle taken when confidence is below the threshold or the answer cannot be resolved |
confidenceThreshold | number | Unset | Optional, 0–1 (frontend step 0.01); applies to choice/score only |
Question-type behavior:
choice: the model picks one ofoptions. Each option becomes an output handle.score: the model rates the state against the ordered levels inoptions; the highest-probability level decides the branch, and the numericscoreis exposed as an output too.noul: returns a0–1yes/no probability;>= 0.5routes toyes, otherwiseno.nouldoes not return aconfidence.
Branch handles:
choice/score: one handle per option/level, plus the fallback handle (defaultby default).noul: fixedyesandno, plus the fallback handle.- Renaming options remaps existing connections onto the new handles where possible (
remapDecisionBranchEdges); handles that cannot be mapped are flagged as errors by the validator (decisionBranchHandleInvalid) and must be reconnected. - Decision nodes that previously used
yes/noas their options are auto-migrated on load (migrateLegacyDecisionBranchEdges).
Output variables:
answer(string): the selected option/level, oryes/noselected_handle(string): the branch handle actually activated (may be the fallback handle)usage(object): decision-model token usagechoice+confidence+probabilities(forchoice)score+confidence+probabilities(forscore)noul(number): yes/no probability (fornoul)
Failure paths
Missing modelId, stateTemplate, or instructions, an invalid questionType, or an option count/uniqueness violation makes the node return validation_error directly; an answer type or probability key set that does not match the configuration returns decision_result_missing — it does not silently fall through to the default branch.
Retries (node-level)
As a workflow node, the Decision node is subject to the node-level retry policy (backend/app/services/workflow/retry.py): the default is RetryPolicy(max_retries=2, base_delay=1.0), i.e. up to 2 retries (3 attempts total), with exponential backoff (base 2.0) plus up to 25% jitter and a per-delay cap of 60 seconds. When enable_retry is true (the WorkflowOrchestrator default) the orchestrator wraps the executor in RetryableExecutor, so failed results such as validation_error and decision_result_missing are retried too. This retry comes from the node policy, not from the TypeSafe adapter (the decision adapter has no retry configuration of its own).
3. Media Generation Node (media_generation)
Configuration container: node.data.mediaGenerationConfig or node.data.config.
| Field | Type | Default | Description |
|---|---|---|---|
mode | string | "image" | Media mode: "image" or "video" |
modelId | UUID string | Required | Team-authorized image/video model ID |
prompt | string | Required | Positive prompt supporting variable interpolation |
negativePrompt | string | null | Negative prompt (image generation only) |
width / height | int/null | null | Image dimensions; when omitted, determined by upstream model or tool settings |
numImages | int | 1 | Number of images; the model or tool configuration determines the upper bound |
referenceImageVariable | string | null | Reference image variable for image-to-image workflows |
duration | float/null | null | Video duration; when omitted, the tool configuration supplies its default |
aspectRatio | string/null | null | Video aspect ratio; when omitted, the tool configuration supplies its default |
motionIntensity | float/null | null | Video motion intensity |
Outputs:
result: Generated media URL. Returns an array of URL strings for images, or a single URL string for video.
4. Condition Branch Node (condition)
Configuration container: node.data.conditionConfig or node.data.config.
Evaluates tree-structured condition groups. Each condition consists of variable (variable reference), operator (comparison operator), and value (target value).
Supported Operators:
- Equality:
equals,not_equals - Text Patterns:
contains,not_contains,starts_with,ends_with,regex_match - Numeric Comparison:
greater_than(>),less_than(<),greater_or_equal(>=),less_or_equal(<=) - Null & Empty States:
is_empty,is_not_empty,is_null,is_not_null
5. HTTP Request Node (http_request)
Configuration container: node.data.config.
| Field | Type | Default | Description |
|---|---|---|---|
method | string | "GET" | HTTP method: GET, POST, PUT, DELETE, etc. |
url | string | Required | Destination URL supporting dynamic template variables |
headers | object | {} | Key-value request headers supporting template variables |
body | any | null | Request payload (supports JSON objects or text interpolation) |
timeout | int | 30 | Request timeout in seconds; the executor default is 30 and this node layer has no additional range validation |
SSRF Protection Guardrails (YUN-150)
All outbound targets from HTTP Request nodes are strictly validated through validate_external_http_url after DNS resolution:
- Private RFC 1918 subnets (
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16), loopback (127.0.0.1,localhost), and cloud metadata (169.254.169.254) are blocked by default. - Internal requests are only permitted if the target IP/CIDR/domain is explicitly allowlisted in Site Settings > SSRF Outbound Targets (
ssrf_allowed_targets) (e.g., allowlistinglocalhost/localor specific enterprise subnets). - Critical non-bypassable ranges (
169.254.0.0/16,224.0.0.0/4,0.0.0.0/32) and Google Cloud metadata (metadata.google.internal) cannot be bypassed or accepted in allowlist configuration and remain permanently blocked.
Outputs:
statusCode(int): HTTP response status code (e.g.,200,404)body(any): Parsed JSON object, or raw string if response is not valid JSONheaders(object): Key-value response headers
6. Knowledge Retrieval Node (knowledge_retrieval)
Configuration container: node.data.knowledgeRetrievalConfig.
| Field | Type | Default | Description |
|---|---|---|---|
knowledgeBaseId | UUID string | Required | Target knowledge base identifier |
querySource | string | "variable" | Query source: "variable" or "constant" |
queryVariableRef | string | "" | Variable reference used when querySource is "variable" |
queryConstantValue | string | "" | Fixed query text used when querySource is "constant" |
searchMode | string | "hybrid" | Search mode: "hybrid", "vector", or "fulltext" |
topK | int | 5 | Maximum number of chunks to return |
threshold | float | 0.0 | Similarity score cutoff threshold |
outputVariable | string | "results" | Custom output variable name for retrieved chunks |
Outputs:
results(array): Array of chunk objects containingcontent,score,metadata,documentId, andchunkIdcontext(string): Pre-concatenated text blocks separated by\n\n---\n\nfor direct prompt injectiontotalFound(int): Total count of matching chunks
7. Code Execution Node (code)
Configuration container: node.data.codeConfig or node.data.config.
Runs inside an isolated sandbox container with a default 30-second timeout (CODE_TIMEOUT = 30).
- Python Entry: with
language: "python", must definedef main(inputs):, whereinputsis a dictionary, returning adict. - JavaScript Entry: with
language: "javascript", must definefunction main(params)orconst main = (params) =>, returning anobject. - Any other
languagevalue is rejected (unsupported_code_execution_language).
Outputs: All top-level keys returned in the dictionary/object are mapped to individual downstream variables.
8. Data Transformation Nodes
Template Transform (template)
- Container:
node.data.templateConfig. template: Jinja2 template string, e.g.Hello {{ user_name }}, ticket #{{ order_id }} is updated.inputs: Variable mapping list binding upstream variables to template variables.- Outputs:
output(string) or custom defined output variable name.
Variable Aggregator (variable_aggregator)
- Container:
node.data.variableAggregatorConfig. mode: Aggregation strategy:"object": Bundle variables into a JSON object key-value map"array": Merge variables sequentially into an array list"concat": Join string variables usingseparator"merge": Deep or shallow merge multiple object variables
- Outputs:
result(default).
Variable Assignment (variable_assignment)
- Container:
node.data.variableAssignmentConfig. assignments: List of assignments supporting three operations:overwrite: Overwrite target context variable withvariableRefclear: Clear target variableset: Assign fixedconstantValue
Parameter Extractor (parameter_extractor)
- Container:
node.data.parameterExtractorConfig. extractionMethod: Strategy:"llm"(model reasoning),"regex"(regular expressions), or"json_path"(JSON Path syntax).- Outputs: Each extracted parameter is exposed as an independent strongly typed output variable.
File to URL (file_to_url)
- Container:
node.data.fileToUrlConfig. - Converts incoming binary/temporary file or image variables into permanent or signed public URLs, avoiding large Base64 strings in LLM prompts.
9. Flow Control & Container Nodes
Question Classifier (question_classifier)
- Container:
node.data.questionClassifierConfig. - Configures a language model and multiple preset category branches (with
id,name,description, andhandle). At runtime, prompts the model to classify intent and route along the matching branch handle.
Iteration (iteration)
- Container:
node.data.iterationConfig(withnode.data.configretained for legacy definitions). iteratorVariable: Variable reference to traverse; legacy definitions may useinputVariable.iteratorType:"array"(default) or"object". Array mode wraps scalar input in a one-element array; object mode does not iterate non-object input.- Array mode exposes
itemVariable(default"item") andindexVariable(default"index"); object mode exposeskeyVariable(default"key") andvalueVariable(default"value"). maxIterations: Defaults to100; a positive integer is capped at1000at runtime.
Loop (loop)
- Container:
node.data.loopConfig(withnode.data.configretained for legacy definitions). - Prefer
exitConditions(an array of conditions) together withexitLogicOperator("and"; any other value is handled as"or") to define exit behavior. Each condition containsvariable,operator, andvalue. - When
exitConditionsis absent, the legacyconditionVariable,conditionOperator, andconditionValuefields are used. With neither condition form configured, the loop continues until its iteration count limit. counterVariabledefaults to"loopCount"and falls back to legacyindexVariable;outputVariabledefaults to"results".maxIterationsdefaults to100; the executor appliesmin(configured value, 1000). Supply a comparable integer value: unlike iteration, this path has no additional strict type validation.
Pause (pause)
- Container:
node.data.pauseConfig. mode:"approval"(await human sign-off) or"variables"(await external form input).- Suspends workflow execution and fires an event notification, resuming when input or approval is received.
Output Node (answer)
- Container:
node.data.answerConfig. outputs: Final key-value dictionary presented to the caller (string,number,boolean,array,object).streaming: Can bind directly to an upstream streaming LLM node'sresponseto stream text back to client applications.
Validation Checklist
The workflow editor uses its validation engine to report recognized errors and warnings in the checklist panel, helping authors correct definitions. The publish endpoint does not currently enforce this checklist; authors should address its findings before saving or publishing. Implemented checks include:
- Graph Checks:
- Runtime plan validation requires exactly one
user_inputortriggerentry point and detects cycles in the workflow graph. - The validator flags nodes without an upstream edge, except
user_input,trigger,iteration_start,loop_start, andcomment.
- Runtime plan validation requires exactly one
- Node Configuration Checks:
- Depending on node type, it reports missing models, tools, knowledge bases, extraction parameters, assignments, or processing children inside a container.
condition,question_classifier,decision,code,sub_workflow,agent,media_generation,pause, and variable-processing nodes each have corresponding configuration checks.- The
decisionnode validatesstateTemplate,instructions, option count and uniqueness, and whether any edge still references a stale branch handle (decisionBranchHandleInvalid).
- Variable & Container Checks:
- The editor reports variable references unavailable from the visible upstream graph, invalid or duplicate parameter names, and container-structure issues.
- It also reports placement of
pausenodes inside iteration or loop containers.
Runtime execution still performs node configuration and authorization checks. Passing or ignoring checklist findings does not guarantee that external model, tool, or knowledge base calls will succeed.
How is this guide?