Workflow YAML file format
Stability: provisional — the file format may change in a minor release.
Generated from the models that load and save workflow files, the checks workflow validation runs, and the rules that tie a workflow to its file. Do not hand-edit.
Contents:
- The file — WorkflowFile
workflow— Workflowworkflow.nodes[]— Nodeworkflow.edges[]— Edgeworkflow.exposed_ports— ExposedPortsworkflow.exposed_ports.inputs[]/workflow.exposed_ports.outputs[]— ExposedPort
Example
A workflow that references a subworkflow, and the subworkflow file, as SciStudio saves them.
workflows/tidy-measurements.yaml
workflow:
id: tidy-measurements
version: 1.0.0
description: Load a table and export it through a reusable subworkflow.
nodes:
- id: load
block_type: load_data
config:
core_type: DataFrame
path: data/raw/measurements.csv
layout:
x: 0.0
y: 0.0
- id: export
block_type: subworkflow_block
config:
ref:
path: subworkflows/export-table.yaml
layout:
x: 320.0
y: 0.0
edges:
- source: load:data
target: export:table
metadata: {}
subworkflows/export-table.yaml
workflow:
id: export-table
version: 1.0.0
description: Save a table under data/results.
nodes:
- id: save
block_type: save_data
config:
core_type: DataFrame
path: data/results
layout:
x: 0.0
y: 0.0
edges: []
metadata: {}
exposed_ports:
inputs:
- name: table
internal: save.data
outputs: []
The file — WorkflowFile
A workflow YAML file: one mapping whose only key is workflow.
Workflow files live in the project's workflows/ directory, one workflow per file, with a .yaml or .yml suffix; subworkflow files may live elsewhere in the project. SciStudio writes the keys in the order this reference lists them and leaves out optional keys whose value is null.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
workflow |
Workflow | yes | — | The workflow definition. |
Keys not listed here are ignored when the file loads and are not written back when it is saved.
workflow — Workflow
The workflow body: everything under the top-level workflow key.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | no | "" |
Workflow id. It must equal the file name without its suffix: workflows/main.yaml declares main. The write_workflow agent tool refuses a file whose name and id differ, and moving or renaming a workflow file rewrites the id to the new name (a .swf marker is dropped, so qc.swf.yaml declares qc). A run is identified by its file, not by this value. |
version |
string | no | "1.0.0" |
Version label of this workflow, kept as written. SciStudio does not interpret it. |
description |
string | no | "" |
Human-readable summary of what the workflow does. |
nodes |
list of Node | no | [] |
The blocks in the graph. A workflow with no nodes is valid. |
edges |
list of Edge | no | [] |
Connections between node ports. Leave empty for a workflow with a single block. |
metadata |
mapping | no | {} |
Free-form mapping kept with the workflow. When it holds project_dir, validation resolves project-relative paths in node configuration against that directory. |
exposed_ports |
ExposedPorts or null | no | null |
Ports this workflow offers when another workflow references it as a subworkflow. Without this section the file still runs on its own and exposes no ports. |
Keys not listed here are ignored when the file loads and are not written back when it is saved.
workflow.nodes[] — Node
One block in the workflow graph.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | yes | — | Node id. Edges and exposed_ports refer to the node by this value. Must not be empty; validation reports a duplicate id within the same workflow. |
block_type |
string | yes | — | Registered block type name, as the block registry lists it (for example load_data). The write_workflow agent tool refuses a type the registry cannot resolve; validation reports an unregistered type as a warning. A node that references another workflow file uses subworkflow_block. |
config |
mapping | no | {} |
Block configuration, checked against the block's config schema. When the canvas saves, file and directory fields that point inside the project are written as project-relative paths with forward slashes. A subworkflow_block node names the referenced workflow file, relative to the project, in ref.path. |
execution_mode |
string or null | no | null |
Execution mode recorded with the node: auto, interactive, or external. The engine runs a block in the mode its block class declares. Left out of the file when unset. |
layout |
mapping of string to number or null | no | null |
Canvas position of the node as numbers, for example {x: 120.0, y: 80.0}. It has no effect on execution. Left out of the file when unset. |
Checked when the file loads:
idmust not be empty or whitespace.
Keys not listed here are ignored when the file loads and are not written back when it is saved.
workflow.edges[] — Edge
A directed connection from an output port of one node to an input port of another.
Several edges may share a source: one output feeds several inputs. The edges must not form a cycle, both ends must name nodes in the same workflow, and, when the block registry is available, validation checks that the ports exist and that the output type is accepted by the input.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
source |
string | yes | — | Output port the data leaves from, written node_id:port_name. |
target |
string | yes | — | Input port the data arrives at, written node_id:port_name. |
Checked when the file loads:
sourceandtargetarenode_id:port_name: exactly one colon with a non-empty value on each side.
Keys not listed here are ignored when the file loads and are not written back when it is saved.
workflow.exposed_ports — ExposedPorts
The ports a workflow offers when another workflow references it as a subworkflow.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
inputs |
list of ExposedPort | no | [] |
Input ports of the subworkflow node, each bound to an input port inside this file. |
outputs |
list of ExposedPort | no | [] |
Output ports of the subworkflow node, each bound to an output port inside this file. |
Keys not listed here are ignored when the file loads and are not written back when it is saved.
workflow.exposed_ports.inputs[] / workflow.exposed_ports.outputs[] — ExposedPort
One port a workflow offers to a parent workflow that references it.
internal names the port inside this file with a dot (node_id.port_name), unlike an edge, which uses a colon.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | — | Port name the parent workflow sees on the subworkflow node. A parent edge addresses it as subworkflow_node_id:name. Give each port a distinct name within inputs and within outputs. |
internal |
string | yes | — | The port inside this file that the exposed port stands for, written node_id.port_name with a dot. The node may itself be a subworkflow node, in which case port_name is one of that subworkflow's exposed ports. When a run starts, an internal value naming a node or port that does not exist stops the run. |
Checked when the file loads:
nameandinternalmust not be empty or whitespace.internalisnode_id.port_name: exactly one dot with a non-empty value on each side.
Keys not listed here are ignored when the file loads and are not written back when it is saved.
File name and run identity
Workflow run identity derived from the workflow file.
A workflow is identified at run time by the file it lives in, never by the id: written inside the YAML. The same identity keys the running-workflow guard, the scheduler's event filter, the process registry, the lineage runs.workflow_id column, the pause checkpoint directory, the data/zarr/<identity>/ output directory, and the workflow_id carried on engine and workflow.changed events.
Two forms exist:
workflows/<stem>.yaml— the canonical home of a project workflow — is identified by its stem, soworkflows/main.yamlismain. Existing lineage rows, checkpoints and output directories of correctly named workflows keep their values.- Any other workflow file (a subworkflow under
subworkflows/, a nested file, a.ymlfile) is identified by its project-relative path, written as@followed by the path components joined with@:subworkflows/qc.yamlis@subworkflows@qc.yaml. Inside a component%is written%25and@is written%40.
The path form is a single path segment, so it works unchanged as a directory name, a checkpoint file name and a URL path parameter. A stem never contains /, and a top-level stem that itself starts with @ is given the path form, so no two files share an identity.
Validation
Loading a file checks the shape described above. Validating a workflow — before a run starts, when the canvas saves, and through the validate_workflow agent tool — also checks the graph:
- Duplicate node ids — two nodes share an
id. A workflow with no nodes is valid and skips the remaining checks. - Unresolved subworkflow references — a subworkflow node whose referenced file could not be read when the graph was expanded for a run. Strict mode only.
- Edge format — each edge end is
node_id:port_name. - Edge node references — both ends of an edge name a node in the workflow.
- Cycles — the edges must not form a cycle.
- Unregistered block types — each node whose
block_typethe registry does not know is reported once, as a warning. - Ports and types — both ends of an edge name a port the block has (a missing port is reported as a warning), and the input port accepts the type the output port produces.
- Unconnected required inputs — a required input port has no incoming edge. Strict mode only.
- Port counts — a block with a variable number of ports stays within the minimum and maximum its block type declares.
- Duplicate output extensions — two output ports of one block with variable outputs declare the same file extension (case-insensitive), which would make matching output files to ports ambiguous.
- Code block configuration — a code block's saved configuration, such as a required
script_path, is complete and valid. Strict mode only. - Boundary file formats — each file extension and data type declared on an app or code block port can be written (input ports) or read (output ports) by a registered capability. Strict mode only.
Checks 6 to 12 run only when a block registry is given. Callers treat a message that begins with Warning: as advisory; every other message is an error.
Validation runs in one of two modes. "strict" (default) runs every check. "draft" skips the checks marked strict mode only, so the editor can save a graph that is still being built without errors about unresolved references, unconnected inputs, or unfinished configuration. Run start validates in strict mode, so an incomplete graph still cannot run.
JSON Schema
The JSON Schema of a workflow file, as generated from the loader's models.
{
"$defs": {
"EdgeModel": {
"description": "A directed connection from an output port of one node to an input port of another.\n\nSeveral edges may share a ``source``: one output feeds several inputs. The\nedges must not form a cycle, both ends must name nodes in the same workflow,\nand, when the block registry is available, validation checks that the ports\nexist and that the output type is accepted by the input.",
"properties": {
"source": {
"description": "Output port the data leaves from, written ``node_id:port_name``.",
"title": "Source",
"type": "string"
},
"target": {
"description": "Input port the data arrives at, written ``node_id:port_name``.",
"title": "Target",
"type": "string"
}
},
"required": [
"source",
"target"
],
"title": "EdgeModel",
"type": "object"
},
"ExposedPortModel": {
"description": "One port a workflow offers to a parent workflow that references it.\n\n``internal`` names the port inside this file with a dot\n(``node_id.port_name``), unlike an edge, which uses a colon.",
"properties": {
"name": {
"description": "Port name the parent workflow sees on the subworkflow node. A parent edge addresses it as ``subworkflow_node_id:name``. Give each port a distinct name within ``inputs`` and within ``outputs``.",
"title": "Name",
"type": "string"
},
"internal": {
"description": "The port inside this file that the exposed port stands for, written ``node_id.port_name`` with a dot. The node may itself be a subworkflow node, in which case ``port_name`` is one of that subworkflow's exposed ports. When a run starts, an ``internal`` value naming a node or port that does not exist stops the run.",
"title": "Internal",
"type": "string"
}
},
"required": [
"name",
"internal"
],
"title": "ExposedPortModel",
"type": "object"
},
"ExposedPortsModel": {
"description": "The ports a workflow offers when another workflow references it as a subworkflow.",
"properties": {
"inputs": {
"default": [],
"description": "Input ports of the subworkflow node, each bound to an input port inside this file.",
"items": {
"$ref": "#/$defs/ExposedPortModel"
},
"title": "Inputs",
"type": "array"
},
"outputs": {
"default": [],
"description": "Output ports of the subworkflow node, each bound to an output port inside this file.",
"items": {
"$ref": "#/$defs/ExposedPortModel"
},
"title": "Outputs",
"type": "array"
}
},
"title": "ExposedPortsModel",
"type": "object"
},
"NodeModel": {
"description": "One block in the workflow graph.",
"properties": {
"id": {
"description": "Node id. Edges and ``exposed_ports`` refer to the node by this value. Must not be empty; validation reports a duplicate id within the same workflow.",
"title": "Id",
"type": "string"
},
"block_type": {
"description": "Registered block type name, as the block registry lists it (for example ``load_data``). The ``write_workflow`` agent tool refuses a type the registry cannot resolve; validation reports an unregistered type as a warning. A node that references another workflow file uses ``subworkflow_block``.",
"title": "Block Type",
"type": "string"
},
"config": {
"additionalProperties": true,
"default": {},
"description": "Block configuration, checked against the block's config schema. When the canvas saves, file and directory fields that point inside the project are written as project-relative paths with forward slashes. A ``subworkflow_block`` node names the referenced workflow file, relative to the project, in ``ref.path``.",
"title": "Config",
"type": "object"
},
"execution_mode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Execution mode recorded with the node: ``auto``, ``interactive``, or ``external``. The engine runs a block in the mode its block class declares. Left out of the file when unset.",
"title": "Execution Mode"
},
"layout": {
"anyOf": [
{
"additionalProperties": {
"type": "number"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"description": "Canvas position of the node as numbers, for example ``{x: 120.0, y: 80.0}``. It has no effect on execution. Left out of the file when unset.",
"title": "Layout"
}
},
"required": [
"id",
"block_type"
],
"title": "NodeModel",
"type": "object"
},
"WorkflowModel": {
"description": "The workflow body: everything under the top-level ``workflow`` key.",
"properties": {
"id": {
"default": "",
"description": "Workflow id. It must equal the file name without its suffix: ``workflows/main.yaml`` declares ``main``. The ``write_workflow`` agent tool refuses a file whose name and id differ, and moving or renaming a workflow file rewrites the id to the new name (a ``.swf`` marker is dropped, so ``qc.swf.yaml`` declares ``qc``). A run is identified by its file, not by this value.",
"title": "Id",
"type": "string"
},
"version": {
"default": "1.0.0",
"description": "Version label of this workflow, kept as written. SciStudio does not interpret it.",
"title": "Version",
"type": "string"
},
"description": {
"default": "",
"description": "Human-readable summary of what the workflow does.",
"title": "Description",
"type": "string"
},
"nodes": {
"default": [],
"description": "The blocks in the graph. A workflow with no nodes is valid.",
"items": {
"$ref": "#/$defs/NodeModel"
},
"title": "Nodes",
"type": "array"
},
"edges": {
"default": [],
"description": "Connections between node ports. Leave empty for a workflow with a single block.",
"items": {
"$ref": "#/$defs/EdgeModel"
},
"title": "Edges",
"type": "array"
},
"metadata": {
"additionalProperties": true,
"default": {},
"description": "Free-form mapping kept with the workflow. When it holds ``project_dir``, validation resolves project-relative paths in node configuration against that directory.",
"title": "Metadata",
"type": "object"
},
"exposed_ports": {
"anyOf": [
{
"$ref": "#/$defs/ExposedPortsModel"
},
{
"type": "null"
}
],
"default": null,
"description": "Ports this workflow offers when another workflow references it as a subworkflow. Without this section the file still runs on its own and exposes no ports."
}
},
"title": "WorkflowModel",
"type": "object"
}
},
"description": "A workflow YAML file: one mapping whose only key is ``workflow``.\n\nWorkflow files live in the project's ``workflows/`` directory, one workflow\nper file, with a ``.yaml`` or ``.yml`` suffix; subworkflow files may live elsewhere in the\nproject. SciStudio writes the keys in the order this reference lists them and\nleaves out optional keys whose value is null.",
"properties": {
"workflow": {
"$ref": "#/$defs/WorkflowModel",
"description": "The workflow definition."
}
},
"required": [
"workflow"
],
"title": "WorkflowFileModel",
"type": "object"
}