How-to guide
Build a workflow
The workflow JSON format, input and global variables, input mapping, variable paths and how inputs are resolved.
Prerequisites
- A Kiwi Flow server, and either Studio or the CLI
Workflows are stored and executed as JSON. You can draw them in Studio, which produces the same JSON, or edit the JSON directly.
Top-level structure#
{
"workflowId": "wf_001",
"name": "Workflow name",
"description": "What it does",
"version": 1,
"tags": [],
"isReusable": false,
"maxLoopIterations": 1000,
"inputs": [],
"globals": [],
"activities": [],
"onError": {}
}
isReusable: true allows other workflows to embed this one as a sub_workflow. generationHistory is an append-only audit log of AI-assisted edits and is maintained for you.
Inputs#
Inputs are declared at design time, are immutable once a run starts, and are read as inputs.<name>.
"inputs": [
{ "name": "customerId", "type": "string", "required": true },
{ "name": "orderValue", "type": "number", "required": true },
{ "name": "region", "type": "string", "required": false, "default": "US" },
{ "name": "orderLines", "type": "array", "required": true, "itemType": "object" }
]
Types: string, number, boolean, object, array, date.
Global variables#
Globals are readable by every activity and read as globals.<name>. Any activity can write them with a setGlobals block unless the global is readonly.
"globals": [
{ "name": "authToken", "type": "string", "default": null },
{ "name": "runMode", "type": "string", "default": "live", "readonly": true }
]
An activity#
{
"id": "a1",
"name": "Authenticate",
"type": "http_request",
"inputs": [
{ "name": "url", "value": "https://api.example.com/login" },
{ "name": "method", "value": "POST" }
],
"outputs": [
{ "name": "authToken", "from": "output.body.token" },
{ "name": "statusCode", "from": "output.statusCode" }
],
"setGlobals": [
{ "name": "authToken", "from": "a1.output.authToken" }
],
"onError": { "strategy": "fail", "retries": 2, "retryDelaySeconds": 5 },
"next": "a2"
}
outputs maps values from the activity's raw result into named outputs. setGlobals runs after outputs are written, so a1.output.authToken is available to it. The inputs and outputs each activity type offers are listed in the activity reference.
Input mapping#
Every activity input is mapped in one of four ways:
{ "name": "param", "from": "a2.output.someField" } // a path into the variable bag
{ "name": "param", "value": "a literal" } // a literal value
{ "name": "param", "value": "{{inputs.region}}-{{a1.output.id}}" } // a template string
{ "name": "param", "expression": "inputs.region + '-' + globals.sfx" } // a JavaScript expression
An expression runs in the sandboxed script engine. Templates ({{ ... }}) are interpolated first, so an expression can combine static text and resolved paths.
Variable paths#
| Path | Meaning |
|---|---|
inputs.<name> |
A workflow input |
globals.<name> |
A global variable |
<activityId>.output.<field> |
A named output of a completed activity |
<activityId>.output.<field>.<subfield> |
A deep path into a nested JSON output |
<activityId>.output |
The whole output of an activity |
Deep paths resolve in two passes. The engine first looks for the full dotted remainder as a literal key, then falls back to drilling into the nested JSON. So http_request_1.output.body.UserEmail works whether the activity stored body as nested JSON or a flat key.
How an input gets its value#
If an input has no explicit mapping, the engine tries, in order:
- An explicit mapping (
from,value,expression). - Auto-promotion: an output with the same name on the direct predecessor (the activity whose
nextpoints here). This is disabled at merge points, where you must map explicitly. - A global variable with the same name.
- A workflow input with the same name.
- The activity's own default, or null.
If a required input is still null after all five, the run stops with an InputResolutionException.
Check your work#
kiwi flow workflow-validate --file my-workflow.json
Validation catches schema problems, duplicate activity ids, unknown activity types, dangling references and invalid cycles before the workflow can run.
Expected result
- A workflow that passes
workflow-validateand maps data correctly between activities