Key points
- Steps run in dependency order, not list order. Independent branches run concurrently up to runner capacity.
depends_onvalues are a step name or a qualifiedstep.task; an undefined name fails validation.- The full graph is cycle-checked, and a cycle reports the exact path.
tasksturns one step into a sub-graph. Task names must be unique within the step, and a task depends on another task asstep.task— a bare step name is not a valid task dependency.- Limits: 512 steps, 256 tasks per step, 1024 tasks per pipeline, and 256 dependencies per node with 4096 across the pipeline.
runtime_poolon a step overrides the pipeline pool, which is how one step can be placed on different capacity than the rest.
Examples
- name: checks
depends_on: [verify]
tasks:
- name: licenses
script: |
./scripts/license-check.sh
- name: sbom
script: |
./scripts/sbom.sh > /workspace/sbom.json
- name: report
depends_on: [checks.licenses, checks.sbom]
script: |
echo "checks complete"name: release-service
description: Build, verify, and publish the payments service.
container_image: alpine:3.20
working_directory: /workspace
timeout: 45m
steps:
- name: build
script: |
make build
- name: verify
image: golang:1.24
depends_on: [build]
runtime_pool: ci
volumes:
- build-cache:/root/.cache
script: |
go vet ./...
go test ./...
- name: checks
depends_on: [verify]
tasks:
- name: licenses
script: |
./scripts/license-check.sh
- name: sbom
script: |
./scripts/sbom.sh > /workspace/sbom.json
- name: report
depends_on: [checks.licenses, checks.sbom]
script: |
echo "checks complete" - name: report
depends_on: [checks]Field reference
steps[].depends_onstepstring[]OptionalNone
Steps or qualified producer tasks that must finish first. Values may be a step name or step.task.
depends_on:
- prepare
- prepare.generate-tag- Maximum 256 dependencies per step.
- A runtime output reference (
$steps...) is not a valid dependency value. - Undefined dependency names fail validation.
- The full graph is cycle-checked; a cycle reports the exact path.
services/nopsai/pkg/validation/pipeline.go
steps[].runtime_poolstepstringOptionalPipeline `runtime_pool`, otherwise runner default
Kubernetes runtime pool override for this step. Docker runners ignore it.
runtime_pool: gpusteps[].tasksstep modetask[]ConditionalNone
Multi-task step. Each task defines exactly one of goal or script.
tasks:
- name: unit
script: go test ./...- Maximum 256 tasks per step, 1024 across the pipeline.
- Cannot be combined with
goal,script,include, orapproval. - Task names must be unique within the step.
services/nopsai/pkg/validation/pipeline.go
tasks[].nametaskstringRequiredNone
Unique task name within the step.
name: unit-tests- Must be unique within the step.
tasks[].scripttaskstringConditionalNone
Direct shell task. Mutually exclusive with goal; exactly one of the two is required.
script: go test ./...- Cannot define
mcp_profiles.
services/nopsai/pkg/validation/pipeline.go
tasks[].depends_ontaskstring[]OptionalNone
Tasks in the same step, or qualified step.task producers in an upstream step.
depends_on:
- checkout
- prepare.generate-tag- A bare step name is not a valid task dependency; use
step.task. - Maximum 256 dependencies per task.
- Runtime output references are not valid dependency values.
services/nopsai/pkg/validation/pipeline.go
steps[].tasks (max per step)limitcountOptional256 maximum per step
Maximum number of tasks inside a single step.
step 'build' has 257 tasks; maximum is 256services/nopsai/pkg/validation/pipeline.go
tasks (total)limitcountOptional1024 maximum
Maximum number of tasks across every step in the pipeline.
pipeline has 1025 tasks; maximum is 1024services/nopsai/pkg/validation/pipeline.go
depends_on (per node)limitcountOptional256 maximum
Maximum dependencies declared on a single step or task.
step 'deploy' has 257 dependencies; maximum is 256services/nopsai/pkg/validation/pipeline.go
depends_on (total)limitcountOptional4096 maximum
Maximum dependency edges across the whole pipeline graph.
pipeline has 4097 dependencies; maximum is 4096services/nopsai/pkg/validation/pipeline.go
How it works
Two different things create concurrency. Independent steps run at the same time because nothing orders them; independent tasks inside one step run at the same time inside a single execution context, sharing the step image and environment.
Reach for tasks when the work belongs together and shares setup — a batch of checks against one build — and for separate steps when the work has its own image, placement, or failure meaning.
A dependency is a promise about ordering, not about data. Passing a value is a separate declaration, which the next page covers.
Implementation evidence
services/nopsai/pkg/validation/pipeline.goRules the validator enforces on this directive set.
pkg/models/model.goPipeline, step, and task field definitions.

