Platform

Platform overviewArchitectureWorkflow orchestrationGitOps configurationGovernance and AAAAI and MCPKnowledge and contextRuntime and executionEvidence and monitoring

Use cases

All use casesProduction incidentRelease preparationHotfix to productionSecurity scan triage
Why NopsAIIntegrationsSecurity

Resources

All resourcesAI agent governanceMCP governanceMCP securitySelf-hosted platforms
PricingGitHub

Company

How a run worksAboutContactBook a demo

Variables and scopes

What a pipeline declares it needs, where those values resolve from, and how a scope decides the answer.

ReferenceAutomation authorAdministrator

Key points

  • Pipeline variables is a declaration of what the run requires, not an assignment. Values resolve from the run scope.
  • A declared variable that cannot be resolved fails the run before execution rather than starting with a missing value.
  • A bare name resolves in the run scope; scope/path:NAME resolves in that scope and is injected under the bare name.
  • Names must match ^[A-Za-z0-9_.-]+$, and the same runtime name may not resolve from two different scopes in one place.
  • Step variables apply to every task in the step; task variables are applied afterwards and win.
  • Scope is not team path. Scope decides which values resolve; team path decides ownership and notification.

Examples

What this page addsyaml
variables:
  - RELEASE_CHANNEL
  - platform/shared:ARTIFACT_BUCKET
Pipeline so faryaml
name: release-service
description: Build, verify, and publish the payments service.
container_image: alpine:3.20
working_directory: /workspace
timeout: 45m
variables:
  - RELEASE_CHANNEL
  - platform/shared:ARTIFACT_BUCKET
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"
      echo "channel $RELEASE_CHANNEL, bucket $ARTIFACT_BUCKET"
      ./scripts/mint-token.sh > /nopsai/outputs/PUBLISH_TOKEN
    outputs:
      - name: PUBLISH_TOKEN
        sensitive: true
Result

RELEASE_CHANNEL resolves in the run scope and ARTIFACT_BUCKET in platform/shared; both reach the step as plain environment variables.

Rejected: the same name from two scopesyaml
variables:
  - platform/shared:ARTIFACT_BUCKET
  - platform/staging:ARTIFACT_BUCKET
Result

Rejected: one runtime name may not resolve from two different scopes in the same place.

Field reference

variablespipelinestring[]OptionalNone

Runtime variables the pipeline requires. A bare name resolves in the run scope; scope/path:NAME resolves an explicit scope and injects it as NAME.

Example

variables:
  - REGISTRY_HOST
  - platform/shared:ARTIFACT_BUCKET

Rules
  • Names must match ^[A-Za-z0-9_.-]+$.
  • The same runtime name may not be declared twice, even from different scopes.
  • Scope segments may not be absolute or contain . / ...
Evidence

services/nopsai/pkg/validation/pipeline.go

How it works

The two variables directives are different things that share a name. At the top level it is a list of requirements. On a step or task it is a map of assignments, which is also where runtime outputs are consumed.

Cross-scope use is always explicit. Nothing resolves from another scope unless the reference says so, which keeps a pipeline honest about what it reaches for.

A run can also override variables at start time, and the values a run actually resolved are visible on the run record, which is usually faster than reasoning about scope inheritance.

Implementation evidence

  • pkg/models/runtime_refs.go

    Scoped reference parsing and name validation.

  • services/nopsai/pkg/validation/pipeline.go

    Rules the validator enforces on this directive set.