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

Sub-flows

A flow can invoke another deployed Core via the subflow_call node. The compiler emits an IRCoreCallBlock (kind: "core_call") per the ScaiCore IR spec.

Per-node config#

jsonc
{
  "type": "subflow_call",
  "config": {
    "target": "core://acme/customer-lookup",
    "flow_name": "LookupCustomer",
    "input_bindings": { "customer_id": "{{message.customer_id}}" },
    "instance_key": null,
    "version": null,
    "timeout": "30s",
    "is_async": false
  }
}
  • target — a core://{tenant_slug}/{slug} URI pointing at the called Core. Cross-tenant calls supported if the caller's principal has access on the other tenant.
  • flow_name — optional; targets a specific flow within the called Core when the Core exposes multiple.
  • input_bindings — map of {argument_name: expression}. Expressions can reference the calling flow's scope.
  • instance_key — for entity-mode targets, picks the instance. Pass-through to the runtime.
  • version — pin to a specific Core version. Omit to follow the target's default.
  • timeout — wall-clock budget.
  • is_asynctrue for fire-and-forget; false (default) waits for the sub-flow's result.

Canvas picker#

The Sub-flow Target editor lists the calling tenant's flows from flowsListStore, lets you click one to fill in the core:// URI, and falls back to a free-text URI input for cross-tenant calls.

When to reach for sub-flows#

  • Reuse. A "summarize transcript" flow that lives once and is called from three different parent flows.
  • Specialization. A heavy reasoning step that warrants its own deploy/lifecycle (different model registry, different deploy cadence).
  • Composition with HITL. The sub-flow contains the HITL surface; the parent doesn't have to know about it.
  • Cross-tenant integration. Calling out to a partner-published Core via its core://{partner}/{slug} URI.

When NOT to#

  • "Just to organize the canvas" — large flows are easier to manage as one graph with named sections than as a fan-out of tiny sub-flows.
  • "To split deterministic steps" — @rigid blocks and plugin calls compose cheaply within the same flow. Sub-flows have invocation overhead.

IR shape#

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "kind": "core_call",
  "target": "core://acme/customer-lookup",
  "flow_name": "LookupCustomer",
  "input_bindings": {"customer_id": IRExpression(...)},
  "instance_key": None,
  "version": None,
  "timeout": "30s",
  "is_async": False
}

Per SCAICORE-COMPILER-IR.md §5.9.

YAML shape#

yaml
1
2
3
4
5
6
7
8
steps:
  - core_call:
      target: core://acme/customer-lookup
      flow_name: LookupCustomer
      input_bindings:
        customer_id: "{{message.customer_id}}"
      timeout: 30s
    meta: { node_id: node_abc, node_kind: subflow_call, ... }

The core_call YAML keyword isn't yet shown in ScaiGrid's public scaicore.md example — this is a best-effort emission matching the IR field names. If ScaiGrid's YAML loader doesn't recognize it on your deployment, fall back to --format ir.

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