Operational guidance

CI and Pipelines

How to wire ota into CI without scraping text output.

operatemaintainersbasicstable2026-05-30

What to run in CI

  • Use ota validate for contract correctness.
  • Use ota doctor --json when you want machine-readable readiness and optional grouped finding summaries with stable action_key values.
  • Use ota check --json for non-executing readiness gates; it carries the same additive finding_groups metadata when present, with the same stable action_key shape.
  • Use ota annotations --mode doctor --format plain when the runner needs portable log lines instead of provider-specific annotation syntax.
  • Use ota annotations --mode doctor --format markdown when the platform exposes a step-summary or PR-comment surface and ota should own the explanation.
  • Use ota receipt --json --archive when the pipeline needs the same readiness scan as a durable artifact for later audit or automation. Add --workflow <name> on multi-workflow repos so archive and baseline truth stay inside the intended workflow lane.
  • Use ota annotations --mode receipt-diff --format markdown when baseline drift or fail-on-new-blockers gating should explain what changed without custom JSON parsing.
  • Use ota workspace doctor --json or ota workspace check --json when a workspace contract is involved.

Real pipeline example

Portable shell wrapperbash
#!/usr/bin/env bashset -uo pipefail mkdir -p .ota/ci ota validate --json . | tee .ota/ci/validate.jsonvalidate_status=${PIPESTATUS[0]} ota doctor --json . | tee .ota/ci/doctor.jsondoctor_status=${PIPESTATUS[0]} ota annotations --mode doctor --format plain --input .ota/ci/doctor.json   | tee .ota/ci/annotations.log ota receipt --json --archive . | tee .ota/ci/receipt.jsonreceipt_status=${PIPESTATUS[0]} if [ "${validate_status}" -ne 0 ] || [ "${doctor_status}" -ne 0 ] || [ "${receipt_status}" -ne 0 ]; then  exit 1fi
GitHub Actions wrapperyaml
permissions:  contents: read  pull-requests: write steps:  - uses: actions/checkout@v5  - name: Publish ota readiness    uses: ota-run/action@v1    with:      command: receipt      archive: true      annotate: true      comment-pr: true      github-token: ${{ github.token }}

Why this matters

  • CI should use the same readiness rules humans use.
  • Pipeline output should be machine-readable when tools need to fail or annotate on findings.
  • Step summaries and pull-request comments should sound like ota, not like whatever ad-hoc wrapper happened to be written first.
  • This guidance should work for GitHub Actions, GitLab CI, Buildkite, Jenkins, or any other runner.

How to adapt it

  • keep the runner wrapper specific to the CI system
  • keep ota commands identical across runners
  • use doctor --json as the feedback surface and receipt --json --archive as the durable artifact surface
  • use ota annotations when the platform supports annotations, markdown summaries, or provider-neutral log rendering
  • use --format markdown when the platform has a step-summary or PR-comment surface and you want ota’s compact canonical summary block
  • use --format plain for GitLab CI, Jenkins, CircleCI, Buildkite, or any runner without GitHub annotation syntax
  • install ota in every job that invokes direct ota commands; in GitHub Actions prefer ota-run/setup@v1 with source: contract when the repo already declares agent.bootstrap.ota.source, otherwise use explicit setup inputs and rely on automatic GITHUB_PATH export instead of hand-written PATH glue
  • if the provider skips artifact upload after a failed step, capture statuses first, upload .ota/ci/ and .ota/receipts/, then fail in a final step

Provider shapes

  • GitHub Actions: use ota-run/action@v1 when you want step summaries, annotations, pull-request comments, and uploaded receipt artifacts without hand-written glue; when the wrapper itself should own installation, it can consume agent.bootstrap.ota.source through source: contract
  • GitHub Actions: use ota-run/setup@v1 with source: contract when later steps need direct ota commands and the repo already declares agent.bootstrap.ota.source; use its explicit inputs when the workflow intentionally chooses the ota version itself
  • GitLab CI: use artifacts:when: always so blocked readiness gates still keep .ota/ci/ and .ota/receipts/
  • Jenkins: archive .ota/ci/** and .ota/receipts/** in post { always { ... } }
  • CircleCI: store .ota/ci and .ota/receipts as artifacts before the final fail step