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

Reusable steps and child pipelines

Pulling in a shared step definition, and launching another pipeline as part of this one.

ReferenceAutomation authorDeveloper

Key points

  • include: step:<identifier> expands a reusable step definition in place; include: pipeline:<identifier> launches a child pipeline.
  • include cannot be combined with tasks, goal, script, or approval, and an included step cannot define mcp_profiles.
  • Only a pipeline: include may declare parent-visible outputs, and only with sync: true.
  • sync: true makes the parent wait for the child; without it the child runs independently.
  • A child pipeline is a real run with its own record, so it carries its own logs, approvals, and history.

Examples

What this page addsyaml
  - name: checkout
    include: step:platform/shared/checkout

  - name: deploy
    depends_on: [publish]
    include: pipeline:platform/deploy-service
    sync: true
    outputs:
      - name: DEPLOY_ID
Pipeline so faryaml
name: release-service
description: Build, verify, and publish the payments service.
container_image: alpine:3.20
working_directory: /workspace
timeout: 45m
display_option: list
llm_enabled: true
model: reasoning-large
agent_role: senior-release-engineer
governance_level: strict
mcp_profiles:
  - jira-readonly
knowledge_context:
  - kind: guardrail
    ref: security/repo-check
    required: true
llm_content_preload: false
llm_content_include:
  - "src/**/*.go"
llm_content_ignore:
  - "**/testdata/**"
variables:
  - RELEASE_CHANNEL
  - platform/shared:ARTIFACT_BUCKET
steps:
  - name: checkout
    include: step:platform/shared/checkout

  - name: build
    depends_on: [checkout]
    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
        ignore_failure: true
        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: risk-review
        depends_on: [checks.sbom]
        goal: Review the changed files and list the risks this release carries.
        model: reasoning-large
        governance_level: advisory
        mcp_profiles:
          - jira-readonly
        knowledge_context:
          - kind: example
            path: .nopsai/docs/risk-review-example.md
      - 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]
    secrets:
      - REGISTRY_TOKEN
      - platform/shared:SIGNING_KEY
    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
      ./scripts/sign.sh --key "$SIGNING_KEY" --token "$REGISTRY_TOKEN"
    outputs:
      - name: PUBLISH_TOKEN
        sensitive: true

  - name: announce
    depends_on: [package]
    condition: Only run when the release channel is stable.
    ignore_failure: true
    script: |
      ./scripts/announce.sh

  - name: production-gate
    depends_on: [package]
    approval:
      type: production-release
      teams:
        - platform/sre
      allow_self_approval: false
      timeout: 24h

  - name: publish
    depends_on: [production-gate]
    script: |
      ./scripts/promote.sh

  - name: release-notes
    depends_on: [publish]
    goal: Read the commits since the last tag and write release notes to /workspace/NOTES.md.
    model: reasoning-large
    agent_role: release-writer
    governance_level: advisory
    mcp_profiles:
      - github-readonly
    knowledge_context:
      - kind: policy
        ref: platform/release-notes
        required: true

  - name: deploy
    depends_on: [publish]
    include: pipeline:platform/deploy-service
    sync: true
    outputs:
      - name: DEPLOY_ID
Result

The shared checkout step runs first, and the deployment runs as its own child run whose DEPLOY_ID comes back to the parent.

Rejected: child outputs without syncyaml
  - name: deploy
    include: pipeline:platform/deploy-service
    outputs:
      - name: DEPLOY_ID
Result

Rejected: a pipeline: include may only declare outputs with sync: true.

Field reference

steps[].includestep modestringConditionalNone

step:<identifier> expands a reusable step definition. pipeline:<identifier> launches a child pipeline.

Example

include: pipeline:platform/deploy-service

Allowed values

step:<identifier>, pipeline:<identifier>

Rules
  • Cannot be combined with tasks, goal, script, or approval.
  • Cannot define mcp_profiles.
  • Only pipeline: includes may declare parent-visible outputs, and only with sync: true.
Evidence

services/nopsai/pkg/validation/pipeline.go

steps[].syncstep modebooleanConditionalfalse

Runs a pipeline: include synchronously so the parent waits for the child and can import its outputs.

Example

include: pipeline:platform/deploy-service
sync: true

Rules
  • Required when a pipeline: include declares outputs.
Evidence

services/nopsai/pkg/validation/pipeline.go

How it works

Reusable steps are for the work every pipeline repeats — checkout, setup, a standard scan — kept in one definition so a fix lands everywhere. Child pipelines are for work that has its own lifecycle and deserves its own run record.

The sync rule follows from that: a value can only cross the boundary if the parent actually waited for it. Declaring outputs on an async child would be a promise the graph cannot keep.

Because a child is its own run, it resolves its own scope and its own access checks. Including a pipeline does not lend it the parent caller’s permissions.

Implementation evidence

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

    Rules the validator enforces on this directive set.

  • doc/runtime-flows.md

    Child pipeline launch, synchronisation, and output resolution.