Skip to content

YAML Pipelines

PocketCI supports two pipeline formats: JavaScript/TypeScript (the primary format) and Concourse-compatible YAML. YAML pipelines are a good fit if you're migrating from Concourse CI or prefer a declarative style for resource-driven workflows.

Pipeline Structure

A YAML pipeline has three top-level sections:

yaml
resource_types: [] # optional — custom resource type definitions
resources: [] # resources to get/put during jobs
jobs: [] # the work to execute

Resources

Resources represent external artifacts (git repos, S3 buckets, container images, etc.) that jobs fetch or publish:

yaml
resource_types:
  - name: mock
    type: registry-image
    source:
      repository: concourse/mock-resource

resources:
  - name: source-code
    type: mock
    source:
      force_version: "1.0"

The built-in resource type is registry-image. Any additional type must be declared under resource_types.

Jobs

Each job has a plan — an ordered list of steps to execute:

yaml
jobs:
  - name: build
    plan:
      - get: source-code
      - task: compile
        config:
          platform: linux
          image_resource:
            type: registry-image
            source:
              repository: golang:1.22
          run:
            path: go
            args: ["build", "./..."]

Step Types

StepDescription
taskRun a command in a container
getFetch a resource version
putPublish to a resource
doGroup steps sequentially
tryRun steps, absorbing failures
in_parallelRun steps concurrently
acrossFan-out steps over a set of values
attemptsRetry a step on failure
notifySend a notification
agentRun an LLM agent step

task

The most common step. Runs a command inside a container:

yaml
- task: run-tests
  config:
    platform: linux
    image_resource:
      type: registry-image
      source:
        repository: busybox
    run:
      path: sh
      args: ["-c", "echo hello"]
  timeout: 10m

Task Configuration Reference

run — working directory

Use run.dir to set the working directory inside the container. Relative paths are resolved under /workspace; absolute paths are used as-is.

yaml
- task: test
  config:
    platform: linux
    image_resource:
      type: registry-image
      source:
        repository: golang
    inputs:
      - name: repo
    run:
      dir: repo # → /workspace/repo
      path: go
      args: [test, ./...]

env — environment variables and secrets

Pass environment variables to the task. Values prefixed with secret: are resolved from the pipeline's secrets store at runtime:

yaml
- task: deploy
  config:
    ...
    env:
      DEPLOY_ENV: production
      API_TOKEN: "secret:DEPLOY_API_TOKEN"  # resolved from secrets

See Secrets for how to register secrets.

limits — container resource limits

Control CPU and memory allocation for the container. Supported by the Fly.io driver; other drivers may ignore these fields.

FieldTypeDescription
cpuintNumber of vCPUs
memorystringMemory with unit suffix: 512MB, 4GB, 2GiB
cpu_kindstringCPU class: shared (default) or performance
yaml
- task: heavy-build
  config:
    platform: linux
    limits:
      cpu_kind: performance # dedicated CPUs (Fly.io)
      cpu: 4
      memory: 8GB
    image_resource:
      type: registry-image
      source:
        repository: golang
    run:
      path: go
      args: [build, ./...]

performance CPUs provide dedicated (non-shared) compute. Memory for performance machines is rounded up to the nearest 1 GB; shared machines round to the nearest 256 MB.

notify

Send a notification to a configured backend (Slack, Teams, HTTP webhook). The notify key is the name (or list of names) of a notification config registered with the pipeline.

yaml
# Inline message with Go/Sprig template
- notify: my-webhook
  message: "Build {{ .JobName }} finished: {{ .Status | upper }}"

# Multiple destinations
- notify:
    - slack-channel
    - teams-webhook
  message: "Deploy done"

# Fire-and-forget (does not block or fail the step on error)
- notify: audit-log
  message: "Pipeline {{ .PipelineName }} started"
  async: true

# Load the message template from a file in a prior task's output volume
- notify: my-webhook
  message_file: task-output/message.txt

The message and message_file fields are rendered as Go text/template strings with Sprig functions. The template context exposes .PipelineName, .JobName, .BuildID, .Status, .StartTime, .EndTime, .Duration, .Environment, and .TaskResults.

When message_file is set it takes precedence over message. The path format is <volume-name>/<relative-path>, matching the same convention used by taskfile: and agent prompt_file: fields.

get / put

Fetch and publish resources:

yaml
- get: source-code
  passed: [build] # only trigger after "build" job succeeds

- put: artifact-store
  params:
    file: output/binary

in_parallel

Run steps concurrently with optional concurrency limit:

yaml
- in_parallel:
    limit: 2
    fail_fast: true
    steps:
      - task: lint
        config: ...
      - task: unit-tests
        config: ...
      - task: integration-tests
        config: ...

do / try

Group steps or absorb failures:

yaml
- do:
    - task: step-a
      config: ...
    - task: step-b
      config: ...
  on_success:
    task: notify-success
    config: ...

- try:
    - task: optional-step
      config: ...

Job Dependencies

Use passed constraints on get steps to define a dependency between jobs. The dependent job only runs after the specified job has successfully used the same resource:

yaml
jobs:
  - name: build
    plan:
      - get: source-code
      - task: compile
        config: ...

  - name: deploy
    plan:
      - get: source-code
        passed: [build] # waits for "build" to succeed
      - task: deploy-app
        config: ...

Step and Job Hooks

Hooks run conditionally based on outcome. They can be attached to any step or to the job itself:

HookTriggers when
on_successStep/job succeeded
on_failureStep/job failed (non-zero exit)
on_errorStep/job errored (infrastructure issue)
on_abortStep/job was aborted (timeout or cancellation)
ensureAlways — runs regardless of outcome
yaml
jobs:
  - name: deploy
    plan:
      - task: run-migration
        config: ...
        on_failure:
          task: rollback
          config: ...
    on_success:
      task: notify-success
      config: ...
    ensure:
      task: cleanup
      config: ...

Concurrency Control

Limit how many runs of a job can be active simultaneously:

yaml
jobs:
  - name: deploy
    max_in_flight: 1 # only one deploy at a time
    plan:
      - task: deploy
        config: ...

Template Preprocessing

YAML pipelines support Go text/template syntax for dynamic content. Opt in by adding a comment at the top of the file:

yaml
# pocketci: template
jobs:
  - name: {{ .Env.BUILD_ENV }}-deploy
    plan:
      - task: deploy
        config: ...

See the Templating guide for full details.

Known Limitations

PocketCI's YAML support is intentionally scoped. The following are not supported:

  • Overlay/btrfs volume management (container runtimes handle volumes natively)
  • Tasks spread across multiple workers within a single job
  • Full Concourse feature parity (this is a compatibility layer, not a reimplementation)