Skip to main content
Version: v0.2.1

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