Kasimir Docs DEEN To the app →

Workflow Node Reference

Complete reference of every Kasimir workflow node type with config fields, inputs/outputs, ports, and limits.

This reference documents every node type executed by the Kasimir workflow engine (server/utils/workflowExecutor.ts). The engine is a linear walker along the edges (workflow_edges): starting from the trigger node it follows an edge queue; multiple edges out of one port run sequentially in enqueue order (Make.com semantics), and each node runs at most once per run (diamond-join: first branch wins). Values flow through an in-memory InterpolationState map and are resolved in downstream nodes via the template reference {{slug.field[.path]}}. All *_template fields pass through interpolate(); the node-type literal (type) inside config is the discriminator of the NodeConfig union.

Core concepts

Reference syntax (interpolation)

Templates reference prior nodes via {{slug.field[.path]}}. The regex allows slug = [a-z][a-z0-9_]{0,39}, field = input or output, plus an optional dot-separated path.

Reference

Meaning

{{trigger.input.kw}}

Value of trigger/form input kw

{{step1.output}}

Full output of node step1 (string or JSON-stringified)

{{step1.output.path}}

Path traversal into a JSON output object

{{loop.output.item}} / {{loop.output.index}}

Current item / index inside a for_each

{{ask.input.answer}}

An answer from an ask_user node

ℹ️

Missing references do NOT error: unresolvable refs yield the placeholder string [MISSING:slug] or [MISSING:{{…}}]. null/undefined render as ''. Reserved slugs: trigger, now, output, error, headers, status, body.

Cross-cutting node fields

These WorkflowNode fields apply to EVERY node type:

Field

Type

Effect

name

string | null

Display name (display = name || slug); slug stays the technical id for refs

note

string | null

Editor note

disabled

boolean

Node is skipped (status skipped); upstream output passes through unchanged, ALL outgoing edges are followed

on_error

'stop' | 'continue'

stop (default): error aborts the whole run. continue: node marked failed, run proceeds, downstream output = null

retry_count

number (0..5)

On failure the node is re-run up to n times before on_error applies

requires_approval

boolean

Run pauses with status waiting_approval BEFORE execution until someone approves

ai_fields

Record<string,{mode:'auto'|'prompt';prompt?}>

AI-filled config fields; resolveAiFields replaces affected *_template strings before execution

ai_model_slug

string | null

Model used for AI-field resolution

⚠️

A pause (ask_user, delay, requires_approval) behind a router or parallel branches is NOT supported — the run fails with a corresponding message if the edge queue is non-empty at pause time.

Workflow-Engine · Kanten-Warteschlange Sequenzielle Ausführung des Edge-Queue-Walkers Lauf #4812 aktiv TRIGGER Start output ROUTER Verzweigung 3 Ausgänge A B C BRANCH A LLM-Schritt prompt_llm success / error Rückfrage ask_user · PAUSE wartet auf Eingabe BRANCH B Dokument doc_render true / false BRANCH C · for_each Schleife for_each Body transform Sammeln aggregate loop-back Kanten-Queue FIFO · Walker-Reihenfolge 1 start → router 2 router → A 3 router → B 4 router → loop 5 A → ask_user ⏸ pausiert bei #5 aktiv erfolg wartend offen
The engine walker: edge queue, router fan-out, for_each/aggregate loop, and pause nodes.

Node overview

type

Category

Output ports

trigger

Entry

output

llm

AI

output

check

AI / guardrail

output

image_gen

AI

output

code

Logic

output

if_else

Branching

true, false

router

Branching

one port id per route (+ fallback)

for_each / aggregate

Loop

output (on aggregate)

http_out

Action

success, error

ask_user

Pause

output

delay

Pause

output

load_table

Data

output

doc_search

Data / RAG

output

web_search

Data

output

doc_render

Output

output

save_to_storage

Output

output

output

Output

output

send_email

Action

output

post_message

Action

output

notify

Action

output

outlook_draft / outlook_send / outlook_event

Integration (Microsoft)

output

onedrive_upload

Integration (Microsoft)

output

teams_card

Integration (Microsoft)

output

gdrive_upload / gcal_event / gsheets_append

Integration (Google)

output


Entry

trigger

Every workflow has exactly one trigger; if missing, the run fails immediately (Kein Trigger-Knoten). The trigger defines the input variables available as {{trigger.input.<key>}}. It runs no logic itself — the run inputs are written to state, the node is marked completed, and the output edge is followed.

Config field

Type

Description

mode

'manual'|'webhook'|'schedule'|'form'|'integration'

Trigger kind

inputs

WorkflowInputDef[]

Input variables (shared across modes)

integration_provider

string | null

Only for integration (e.g. jira, confluence)

integration_trigger

string | null

Trigger key from INTEGRATION_TRIGGERS

integration_config

Record<string,string> | null

Provider-specific fields

WorkflowInputDef: key ([a-z][a-z0-9_]{0,39}), label, type (text/longtext/select/boolean), placeholder?, required, options? (select only), default_value?. Required fields are validated at run start; optional empty fields stay as '' / false.

The Outlook-mail trigger exposes a FIXED variable set: from, subject, to, cc, body, received_at, message_id, attachments.


AI nodes

llm

The central text-generation node. Free text is streamed (partial flush to output_text_partial every 300 ms, stream deadline 120 s); structured output and the agentic path run non-streaming.

Config field

Type

Description

model_slug

string | null

null ⇒ order: assistant default ⇒ workflow.default_model_slug

system_prompt

string | null

System prompt (interpolated); the current date is always prepended

user_prompt_template

string

User prompt (interpolated)

attached_documents

string[]

Subset of the workflow_documents pool

web_search

boolean

Legacy; without tools maps to ['web_search','fetch_page']

tools

string[]

Agentic tools; non-empty ⇒ reasoning loop (structured_output then inactive)

memory_session_key

string

Interpolated; non-empty ⇒ conversation memory active (except with structured_output)

memory_window

number

Number of prior interactions loaded (default 5)

structured_output

boolean

Forces a JSON-schema response

output_schema

Record<string,unknown> | null

JSON schema when structured_output

temperature

number | null

null ⇒ provider default

max_steps

number

Max iterations of the tool loop (clamp 1..25, default 6)

ai_app_id

string | null

Reuse an existing assistant (supplies persona/model/web tools; node values take precedence)

Output: free-text string, JSON object (structured), or agent answer. tokens_in/tokens_out are captured. With structured_output and unparseable JSON a retry runs with "Reply exclusively as valid JSON."; if that also fails → error. Available agentic tools: web_search, fetch_page, doc_search. The agentic loop has a 150 s wall-clock deadline and drops the tools on the last allowed iteration to force a final answer.

check (guardrail / "Review")

LLM-based content classification returning a verdict. GDPR-relevant.

Config field

Type

Description

input_template

string

Text to evaluate (interpolated)

checks

CheckKind[] (≥1)

moderation, pii, jailbreak

model_slug

string | null

null ⇒ workflow default

Output (JSON): { passed, flags[], reason (German), checks[] }. passed is false as soon as any enabled check fires. Unparseable model reply ⇒ passed=false, flags=['parse_error'].

image_gen ("Image generation")

Text prompt → OpenAI-compatible /images/generations via the LiteLLM proxy; stores a PNG.

Config field

Type

Description

prompt_template

string

Image prompt (interpolated)

model_slug

string | null

null ⇒ workflow default (should be an image model)

size

'1024x1024'|'1024x1792'|'1792x1024'

Image size

n

number (1..4)

Number of images

Output: { path } (path in workflow-outputs, output_file_path). The response is requested as b64_json; missing image data → error. Runtime requires an image model configured in LiteLLM (ops dependency).


Logic

code

Runs LLM/user-written Python in the kasimir-codebox sidecar (timeout 30 s). If the sandbox is not configured (CODEBOX_BASE_URL/API_KEY), the node fails.

Config field

Type

Description

code

string

Python source

Predecessor outputs are provided as an inputs dict (key = node slug, each {input} or {output}) — base64-embedded and decoded in Python. A helper result(x) prints JSON via print().

Output: trimmed stdout; valid JSON is parsed (structured output), otherwise plain text. Code error/timeout ⇒ node error (stderr truncated to 500 chars).


Branching

if_else

Evaluates a condition and follows port true or false.

Config field

Type

Description

condition

{left, op, right}

Legacy single condition

conditions

Array<{left, op, right}>

Multi-condition; non-empty ⇒ replaces condition

match

'all'|'any'

all = AND (default), any = OR

Operators (op): ==, !=, contains, matches (RegExp), is_empty (empty or [MISSING:…]), is_truthy, is_falsy, >, <, >=, <=. Both sides are interpolated; numeric comparisons cast via Number(). Output port = true/false; output itself is null.

router (Make.com semantics)

ALL routes whose conditions match are activated and run sequentially. A route with no conditions always runs; the "else" route (is_fallback) runs only if NO other matched.

Config field

Type

Description

routes

RouterRoute[]

List of routes

RouterRoute: id (= port id / edge.from_port), label, conditions[], match (all/any), is_fallback?. Output: { matched_routes: string[] }; output_port = comma-separated list of matched route ids; the walker enqueues the edges of ALL matched ports.


Loop

for_each + aggregate

for_each evaluates over_expr to an array and runs the LINEAR body chain from the output port up to the next aggregate node once per item.

for_each field

Type

Description

over_expr

string

e.g. {{trigger.input.items}}; array or JSON-array string like ["a","b"]

max_items

number | null

Optional iteration cap; null = all

Per iteration: {{<loopSlug>.output.item}} and .index. If over_expr is a string, JSON.parse is attempted; if it isn't an array ⇒ error.

aggregate field

Type

Description

collect_expr

string

Evaluated per iteration (typically {{step.output}})

mode

'array'|'join_text'

array = JS array, join_text = joined string

separator

string

join_text only (default \n\n)

dedupe

boolean

Remove duplicate (value-equal) entries before output

Output at the aggregate output port: the collected array or joined string.

⚠️

v1 limitations: the body MUST be linear — if_else, router, http_out, ask_user, delay, and nested for_each are forbidden in the body. Exactly one output port; the body must end in an aggregate. Body nodes persist only the LAST iteration as a run-node row. An aggregate reached without a preceding for_each fails the run.


Actions

http_out

External HTTP request with SSRF protection (httpsOnly, blocks private/loopback/metadata hosts; every redirect is re-validated, max 5 hops).

Config field

Type

Description

method

GET|POST|PUT|PATCH|DELETE

HTTP method

url

string

Target URL (interpolated)

query_params

Record<string,string>

Appended query params (interpolated)

headers

Record<string,string>

Headers (values interpolated)

body_mode

none|json|form|raw

Body mode (sets content-type as needed)

body

string

Request body (interpolated)

body_type

text|json

json ⇒ response is parsed

auth_mode

none|bearer|basic

Auth scheme

secret_slot

string | null

Env-declared slot (NUXT_HTTP_SECRET_<SLOT>); unknown slots ⇒ error

timeout_seconds

number

Timeout (default 30)

Output: { status, body, headers }; port = success (status < 400) or error. Timeout/exception ⇒ status:0, port error. Redirects: 301/302/303 → GET + body dropped; 307/308 → method/body preserved.

send_email

Email via SendGrid; body_markdown becomes HTML via marked.

Config field

Type

Description

to_template

string

Must resolve to a valid address (else error)

cc_template / bcc_template

string

Optional; comma/semicolon-separated, valid-only

subject_template

string

Subject

body_markdown_template

string

Markdown body

reply_to

string | null

Optional reply-to

from_name_template

string?

Optional sender display name (address stays the verified sender)

Output: { to, cc, bcc, subject, body, sent }. If SendGrid rejects (missing key/invalid address) ⇒ node error.

post_message

Posts to a chat/webhook endpoint; payload shaped per target.

Config field

Type

Description

target

slack|teams|webhook

Target type

webhook_url_template

string

Webhook URL (interpolated; must be http(s)://)

text_markdown_template

string

Message text

username_template

string?

Slack: optional name override

channel_template

string?

Slack: optional channel override

Payload: Slack {text, username?, channel?}; Teams MessageCard-light; webhook {text, source, workflow_id, node_slug}. Output: { target, status, ok }; non-OK HTTP ⇒ error.

notify ("Send notification")

Writes an in-app notification to the run initiator's inbox. No initiator (scheduled/webhook run) ⇒ no-op.

Config field

Type

Description

message_template

string

Message text (interpolated)

Output: the rendered text.


Pause

ask_user

Pauses the run and collects a form's worth of answers; behaves like a second trigger mid-flow. Run status → waiting_input. /resume re-invokes the executor with {resume}; answers are available as {{<slug>.input.<key>}}.

Config field

Type

Description

title

string

Shown above the form

inputs

WorkflowInputDef[]

Form fields (same shape as trigger)

delay

Time-based pause; run status → waiting_timer, resume_at is set.

Config field

Type

Description

duration_value

number (≥1)

Fixed value

duration_unit

seconds|minutes|hours|days

Unit

duration_template

string?

Interpolated to a number > 0; overrides duration_value


Data

load_table

Loads a workflow-linked table (workflow_documents) from the documents bucket and parses it.

Config field

Type

Description

document_id

string | null

Linked document (null = not chosen ⇒ error)

sheet

string | null

null/empty = first sheet (XLSX only)

has_header

boolean

Row 1 = column names

max_rows

number

Cap (default 1000)

Supports .xlsx and .csv; the document must be linked to THIS workflow (defense-in-depth). Output: { rows: Record<string,string>[], count, columns }. A downstream for_each iterates over {{slug.output.rows}}, fields via {{loop.output.item.<column>}}.

doc_search (RAG)

Semantic search over company-wide document chunks (embedding model → searchChunks).

Config field

Type

Description

query_template

string

Query (interpolated)

scope

company|project

see note

top_k

number

Default 5, cap 20

Output: { chunks: [{document_name, snippet, score}], text }. Similarity threshold 0.55.

⚠️

v1 gap: hits are hard-restricted to scope_type='company' documents (GDPR guard). scope='project' falls back to company-wide search — project-scoped RAG needs an RPC change.

Web search via the configured provider (timeout 20 s).

Config field

Type

Description

query_template

string

Query (interpolated)

max_results

number

Default 5, cap 10

Output: { results: [{title, url, snippet}], text }. No provider configured ⇒ node error Keine Web-Suche konfiguriert.


Output

doc_render

Generates a real file (DOCX/XLSX/PDF/PPTX) and stores it in the workflow-outputs bucket.

Config field

Type

Description

format

docx|xlsx|pdf|pptx

Target format

template_mode

with_template|from_markdown

Render path

template_path

string | null

Template (only with_template, from workflow-outputs)

markdown_input

string | null

Markdown source (interpolated)

output_filename_template

string

Filename (interpolated)

With with_template, all trigger inputs + node outputs are provided as variables. Output: { path } (output_file_path). Path: {company_id}/{workflow_id}/{run_id}/{slug}.{ext}.

save_to_storage

Persists output as a file (survives the run).

Config field

Type

Description

mode

inline|forward

inline: write content_template; forward: copy a file from an upstream node

content_template

string

inline only

source_node_slug

string | null

forward only (slug of a file-producing node)

filename_template

string

Target filename (interpolated)

content_type

string

MIME for inline (e.g. text/markdown)

Output: { path }. Path: {company_id}/{workflow_id}/outputs/{filename}. Missing source path / upload error ⇒ node error.

output

Writes a named value into the run-level outputs map (read-modify-write).

Config field

Type

Description

name

string ([a-z][a-z0-9_]{0,39})

Output key

value_template

string

Value (interpolated)

Output: the rendered string; also merged into workflow_runs.outputs.


Integrations

All integration actions resolve the run actor: for manual runs the initiator (user_id); for webhook/scheduled runs (user_id NULL) the workflow creator (Zapier/Make semantics). If a valid connection or permission is missing (403 from the API), the node fails with a message pointing to /integrations.

Microsoft (Graph)

type

Endpoint

Permission

Key config fields

Output

outlook_draft

POST /me/messages (draft, never sends)

Mail.ReadWrite

to_template, cc_template, subject_template, body_markdown_template

{ draft_id, web_link, subject }

outlook_send

POST /me/sendMail (sends immediately, saveToSentItems)

Mail.Send

to_template (≥1 valid), cc_template, subject_template, body_markdown_template

{ sent, subject, body, recipients }

outlook_event

POST /me/events

Calendars.ReadWrite

subject_template, start_template/end_template (ISO), timezone (IANA, default Europe/Berlin), location_template?, attendees_template?, body_markdown_template?

{ event_id, web_link }

onedrive_upload

PUT /me/drive/root:/{path}:/content

Files.ReadWrite.All

mode (inline/forward), content_template, source_node_slug, filename_template, folder_template

{ item_id, web_url, name }

teams_card

Adaptive Card to a Teams incoming webhook

— (webhook URL is the credential)

destination_id (teams_destinations), title_template, message_template, button_text?, button_url_template?

{ status, ok, title }

teams_card resolves the managed, company-scoped destination and decrypts its webhook URL; a button is added only for a valid http(s) URL.

Google

type

Endpoint

Permission

Key config fields

Output

gdrive_upload

Drive v3 multipart upload

auth/drive

mode (inline/forward), content_template, source_node_slug, filename_template, folder_id_template

{ file_id, web_view_link, name }

gcal_event

Calendar v3 primary/events (sendUpdates=none)

auth/calendar.events

subject_template, start_template/end_template (ISO), timezone, location_template, attendees_template, description_template (plaintext)

{ event_id, html_link }

gsheets_append

Sheets v4 values.append (USER_ENTERED, INSERT_ROWS)

auth/spreadsheets

spreadsheet_id_template, range_template (e.g. Sheet1!A:C), values_template (comma-separated cell values)

{ updated_range }

💡

forward mode (OneDrive/Google Drive/save_to_storage) fetches the bytes via source_node_slug from a doc_render node's output — the typical chain is llm → doc_render → *_upload.

Run status values

Status

Meaning

queued / running

Queued / executing

completed / failed / cancelled

Finished / failed / cancelled

waiting_input

Paused in ask_user

waiting_timer

Paused in delay (resume_at)

waiting_approval

Paused before a requires_approval node

Run-node status: pending, running, completed, failed, skipped. Unreached pending nodes are set to skipped at run end.