Docs

Apps & Interfaces · 07.13

App Orchestration: Chaining Workflows

An App runs several workflows as one pipeline. The App Orchestrator executes dependsOn chains and run-all — and 'order' is a display sort, not a dependency.

OrchestrationChaining

An App is a pipeline, not a pile of workflows

An App usually owns several workflows that are meant to run as one pipeline — discover leads, then greet them, then react to replies, then build and deliver. The App Orchestrator is the executor that makes that real: when a workflow completes, any enabled sibling whose dependsOn includes it is queued through the exact same run queue as every other start (never a forked execution path), and run-all starts every root workflow — one with no dependsOn — so the chain cascades from there. Each workflow carries a small binding on settings.appBinding: order, dependsOn, chainOn, concurrency, enabled, purpose.

Order is a display sort — dependsOn is what actually chains

This is the distinction that trips people up. order is only a sort/tie-break number for the control plane and for the sequence run-all starts roots in — it does not make one workflow wait for another. The real "runs after" chaining — the ticked boxes in the App's control panel — is dependsOn: a list of the workflow IDs that must finish first. Setting order: 1,2,3 with empty dependsOn gives you a tidy display list where all three are still roots that fire together. To make them run one-after-another you must wire dependsOn.

agentis.workflow.chain: sequence, or fine-grained bindings

Agents and the UI persist these bindings through agentis.workflow.chain. The ergonomic path is sequence: [id1, id2, id3] — it sets both the order and the dependsOn chain (each depends on the previous) in one call, which is what "run these in order" almost always means. For anything more intricate — a fan-out where two workflows both depend on one upstream, a mix of chainOn: "always" vs the default "success", or concurrency: "exclusive" to skip an orchestrated start while a run is still active — pass the per-workflow workflows array instead. The tool validates every dependency is a real sibling, rejects self-dependencies and cycles, and returns chained: true/false so a hollow order (a sort with no real links) is called out rather than silently accepted.

Safe by construction

Chain depth is capped per lineage by walking the parentRunId chain, so even a mistaken dependsOn cycle terminates instead of looping forever, and the cycle check on workflow.chain stops most of them from ever being written. A workflow can also be enabled: false to keep it in the App but out of the pipeline — the reversible alternative to workflow.delete when you only want it to stop. Every binding change publishes a realtime event, so the App control plane and the canvas reflect a new order or a deleted workflow live, without a manual reload.

Continue