Skip to main content
Version: v0.2.0

Writing sflow YAML Configurations

Minimal Examples​

Local:

version: "0.1"
variables:
WHO:
value: "World"
workflow:
name: hello
tasks:
- name: greet
script:
- echo "Hello ${WHO}"

SLURM with container:

version: "0.1"
variables:
SLURM_ACCOUNT: { value: my_account }
SLURM_PARTITION: { value: my_partition }
backends:
- name: slurm_cluster
type: slurm
default: true
nodes: 1
partition: ${{ variables.SLURM_PARTITION }}
account: ${{ variables.SLURM_ACCOUNT }}
gpus_per_node: 8
operators:
- name: my_container
type: srun
container_image: nvcr.io/nvidia/pytorch:24.07-py3
container_writable: true
mpi: pmix
workflow:
name: my_workflow
tasks:
- name: train
operator: my_container
script:
- python train.py

Key Concepts​

SectionRequiredPurpose
versionYesMust be "0.1"
variablesNoParameters: ${{ variables.X }} / ${X}
artifactsNoNamed URIs (fs://, file://)
backendsNoCompute: local or slurm
operatorsNoExecution: bash or srun (containers)
workflowYesName, timeout, and task list

For complete field reference, see schema-reference.md. For full docs: configuration, variables, artifacts, backends, operators, probes, replicas, resources, modular-workflows.

Essential Patterns​

Variables: Two Access Modes​

  • YAML (plan-time): ${{ variables.NAME }}
  • Scripts (runtime env var): ${NAME}

Expressions support Jinja2 filters: ${{ variables.TP_SIZE * variables.DP_SIZE }}, ${{ [variables.X, 1] | max }}, ${{ 8180 if variables.Y > 1 else 8000 }}.

When using arithmetic or comparisons in expressions, set the variable type correctly (integer, string, etc.) -- otherwise values default to strings and operations like * or > will produce unexpected results.

file:// Artifacts for Helper Scripts​

Always use file:// artifacts with content for multi-line scripts. Never embed Python in YAML via heredocs or python3 -c -- quoting breaks when YAML -> shell -> Python nests.

artifacts:
- name: MY_SCRIPT
uri: file://helper.py
content: |
import sys
print(f"Hello from {sys.argv[1]}")
workflow:
tasks:
- name: run_helper
script:
- python3 ${{ artifacts.MY_SCRIPT.path }} "world"

Container Reuse​

Use container_name + --container-image in extra_args. The first task pulls the image; subsequent tasks attach by name instantly:

operators:
- name: my_runtime
type: srun
container_name: my_container
container_writable: true
mpi: pmix
extra_args:
- --container-image=${{ variables.MY_IMAGE }}

Probes​

TypeUse ForKey Fields
tcp_portInfra servicesport, timeout, interval
log_watchServer readinessregex_pattern, timeout, interval

Always add failure.log_watch for "Traceback (most recent call last)" on server tasks.

Replicas & Sweeps​

  • policy: "parallel" -- all at once; downstream waits for all
  • policy: "sequential" -- one after another; good for sweeps
  • variables with domain -- Cartesian product sweep

Modular Composition​

sflow run -f slurm.yaml -f common.yaml -f sglang/agg.yaml -f bench.yaml \
--missable-tasks prefill_server --missable-tasks decode_server

Merge rules: version must match, named items merge (later wins), tasks concatenate.

GPU Resource Planning​

GPUs per worker = TP * DP * PP  (common default, but varies by framework)
Total GPU slots = GPUs_per_worker * replicas (per task)
Nodes needed = ceil(total_slots / gpus_per_node)

The TP * DP * PP formula is a common pattern but not universal -- some frameworks calculate GPU requirements differently (e.g., attention DP, expert parallelism). When unsure, ask the user or check the framework's documentation for the correct GPU count.

Common Pitfalls​

  1. Missing version: "0.1" in every file (including fragments)
  2. Using ${{ task.X.nodes }} in YAML fields (only works in scripts)
  3. --set with undeclared variable (must exist in config first)
  4. Forgetting depends_on (tasks run immediately without it)
  5. GPU oversubscription (sum of GPU counts > nodes * gpus_per_node)
  6. Probe on short-lived tasks (don't probe benchmarks)
  7. Missing --missable-tasks when composing without all task files

Validation​

python scripts/validate_sflow_yaml.py my_workflow.yaml
python scripts/check_gpu_plan.py my_workflow.yaml
sflow run -f my_workflow.yaml --dry-run

Additional Resources​