Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Node kinds

ScaiFlow has 24 node kinds across 9 categories. Each kind maps to a specific ScaiCore construct — the compiler refuses to invent anything that doesn't exist upstream.

This page is conceptual; the node-kinds reference has the per-kind config shape, ports, and IR mapping.

Categories (visual color cue on the canvas)#

Category Color Kinds
Entry Green entry_api, entry_webhook, entry_schedule
LLM Blue llm_rigid, llm_guarded, llm_flexible
Logic Orange logic_decision, logic_loop, logic_parallel
Tool Purple tool_plugin, tool_http
Data Teal data_variable_set
Checkpoint Yellow checkpoint
Queue / HITL Amber queue_publish, queue_consume, hitl_review, hitl_decision, queue_escalation
Compute Indigo compute_provision, compute_exec, compute_file_upload, compute_file_download, compute_destroy
Sub-flow Grey subflow_call

Entry points#

How an invocation starts. Each entry kind compiles to a top-level IRTrigger declaration on IRModule.triggers — NOT to a block in the flow body. The closed set of trigger kinds is {api, webhook, schedule}.

There is no entry_chat — chat reachability is a publish-time concern, handled by flow.config.publish_as_model (see Publish as model).

  • entry_api — HTTP-style invocation. The deployed Core exposes it at POST /v1/modules/scaicore/cores/{id}/invoke. Config: method, path.
  • entry_webhook — same wire shape but typically called from an external system. Config: method, path, auth.
  • entry_schedule — cron-driven trigger. Config: cron (5-field), timezone.

LLM blocks#

The three-tier rigidity spectrum — see Rigidity.

  • llm_rigid — deterministic template, no model call.
  • llm_guarded — bounded LLM call with guard (pre) and validate (post) expressions.
  • llm_flexible — goal-driven LLM call with an optional output schema.

All three pick a model from the flow's registry via llm_role.

Logic#

  • logic_decision — branches to one of N targets based on per-edge conditions. Compiles to a ScaiCore match block; the IR closed set has no separate if kind. Style is if (one or two branches) or switch (multi-branch on a shared subject); both compile identically — switch is the convention where every branch condition references the same subject.
  • logic_loopfor (iterate a collection) or while (loop until condition false; max_iterations is mandatory).
  • logic_parallel — fan-out branches; max_concurrent + fail_fast controls.

Tool calls#

  • tool_plugin — invoke a registered ScaiGrid plugin. Config: plugin, method, args, optional result_binding. Compiles to a plugin_call statement (NOT a block — sits inside the parent rigid block).
  • tool_http — placeholder for direct HTTP. ScaiCore forbids direct HTTP from Core code; this compiles to a plugin_call against an http plugin name (the canonical name isn't finalized in ScaiCore yet — see Troubleshooting).

Data#

  • data_variable_set — bind an expression to a variable name. Compiles to kind: "assign" per the IR doc.

Checkpoint#

  • checkpoint — pause execution. Useful as a standalone deterministic gate or as the underlying block kind for HITL Review.

Queue / HITL#

ScaiQueue is the asynchronous message bus + human-review surface. See Queues and HITL.

  • queue_publishscaiqueue.publish(scope, queue, message_type, payload).
  • queue_consumescaiqueue.consume(scope, queue, consumer_id).
  • hitl_review — single @checkpoint with hitl_target: {scope, queue, hitl_spec}. Runtime auto-publishes the review request and auto-resolves on completion.
  • hitl_decision — lightweight @checkpoint of type "approval", no preceding queue publish. For cases where the agent already routed to a HITL surface.
  • queue_escalationscaiqueue.escalate(...).

Compute (ScaiBunker)#

Sandboxed execution environments. See Sandboxes.

  • compute_provisionscaibunker.create(image, lifecycle). Returns a bunker handle.
  • compute_execscaibunker.exec(command, timeout_s).
  • compute_file_uploadscaibunker.write_file(path, content).
  • compute_file_downloadscaibunker.read_file(path).
  • compute_destroyscaibunker.destroy().

A flow with any compute_* node auto-adds scaibunker to its plugins list and lifts a default bunker capability onto the manifest if the flow's config.bunker is unset.

Sub-flow#

  • subflow_call — invoke another Core. Config: target (a core://{tenant_slug}/{slug} URI), input_bindings, is_async. Compiles to IRCoreCallBlock (kind: "core_call").

Adding a node kind#

Extending the kind set isn't a casual change. You'd need to:

  1. Add it to the JSON Schema's NodeKind enum (packages/flow-schema/schema/v2.json).
  2. Add it to the Pydantic + TS enums.
  3. Add a category + label + color entry.
  4. Add a _emit_* function in apps/compiler/scaiflow_compiler/codegen.py and register it in _DISPATCH.
  5. Add a default-config entry in apps/canvas/src/canvas/nodeDefaults.ts.

Skipping any one of these will compile but break at runtime.

Updated 2026-05-18 16:05:18 View source (.md) rev 3