Key points
- A producer writes a file under the reserved mount
/nopsai/outputswhose name is exactly the output name, then declares it underoutputs. - Output names must match
^[A-Za-z_][A-Za-z0-9_]*$and be unique within one producer. - A consumer reads the value in
variablesas$steps.<step>.outputs.<NAME>, or$steps.<step>.<task>.outputs.<NAME>for a task producer. The reference must be the entire value. - A dependency path to the producer is required, but a direct
depends_onedge is not: a transitive path is enough. - A missing file fails the step with
required output file /nopsai/outputs/<NAME> was not produced. - A step with
tasksdeclares outputs on the tasks instead, and an approval step cannot declare outputs at all. sensitive: truemasks the value wherever logs are rendered while still passing it downstream.
Examples
- name: package
depends_on: [checks]
variables:
BUILD_TAG: $steps.build.outputs.BUILD_TAG
script: |
./scripts/package.sh "$BUILD_TAG"
./scripts/mint-token.sh > /nopsai/outputs/PUBLISH_TOKEN
outputs:
- name: PUBLISH_TOKEN
sensitive: truename: 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
echo "1.0.$(date +%s)" > /nopsai/outputs/BUILD_TAG
outputs:
- name: BUILD_TAG
- 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
sha256sum /workspace/sbom.json | cut -d' ' -f1 > /nopsai/outputs/SBOM_DIGEST
outputs:
- name: SBOM_DIGEST
- name: report
depends_on: [checks.licenses, checks.sbom]
variables:
SBOM_DIGEST: $steps.checks.sbom.outputs.SBOM_DIGEST
script: |
echo "checks complete"
echo "sbom $SBOM_DIGEST"
- name: package
depends_on: [checks]
variables:
BUILD_TAG: $steps.build.outputs.BUILD_TAG
script: |
./scripts/package.sh "$BUILD_TAG"
./scripts/mint-token.sh > /nopsai/outputs/PUBLISH_TOKEN
outputs:
- name: PUBLISH_TOKEN
sensitive: true variables:
URL: "https://registry/$steps.build.outputs.BUILD_TAG"Field reference
steps[].outputsstepoutput[]OptionalNone
Runtime output contract for single-task steps and for sync pipeline: includes. Steps with tasks declare outputs on the tasks instead.
outputs:
- name: IMAGE_TAG
- name: DEPLOY_TOKEN
sensitive: true- Names must match ^[A-Za-z_][A-Za-z0-9_]*$.
- Duplicate output names in one producer are rejected.
- A step with
taskscannot declare step-level outputs. - An approval step cannot declare outputs.
services/nopsai/pkg/validation/pipeline.go
steps[].outputs[].sensitivestepbooleanOptionalfalse
Marks the runtime output value as sensitive so it is masked in run logs.
outputs:
- name: DEPLOY_TOKEN
sensitive: trueNon-sensitive output JSON stays visible in logs so release evidence such as versions and change IDs remains reviewable.
steps[].variablesstepmap<string,string>OptionalNone
Environment overrides applied to every task in the step.
variables:
BUILD_MODE: release- Keys must match ^[A-Za-z0-9_.-]+$.
- A runtime output reference must be the entire value, not embedded in a larger expression.
- Consuming an output requires a dependency path to the producing task.
services/nopsai/pkg/validation/pipeline.go
tasks[].outputstaskoutput[]OptionalNone
Runtime values this task publishes for downstream consumers.
outputs:
- name: IMAGE_TAG- Names must match ^[A-Za-z_][A-Za-z0-9_]*$.
- Duplicate names within one task are rejected.
tasks[].variablestaskmap<string,string>OptionalNone
Task-local environment overrides. Applied after step variables.
variables:
IMAGE_TAG: $steps.prepare.generate-tag.outputs.IMAGE_TAG- A runtime output reference must be the whole value.
- Consuming an output requires a dependency path to the producer.
How it works
Validation separates three failure modes with different messages: referencing a producer that does not exist, referencing an output the producer never declared, and consuming an output with no dependency path. Read the message before rewriting the graph.
Non-sensitive output values stay visible on purpose. Release evidence — versions, digests, image references — is meant to be reviewable after the fact.
RUNTIME_OUTPUT_MAX_BYTES caps a single output value and defaults to 65536 bytes. A step cannot consume its own outputs, and neither can a task.
Limits
- A runtime output reference is never a valid
depends_onvalue.
Implementation evidence
pkg/models/runtime_outputs.goReference parsing for the short and long forms.
services/agent/internal/app/runtime_outputs.goOutput collection and the missing-file failure.
services/nopsai/pkg/validation/pipeline.goRules the validator enforces on this directive set.

