Operational guidance
CI and Pipelines
How to wire ota into CI without scraping text output.
operatemaintainersbasicstable2026-05-30
Recommended next
What to run in CI
- Use
ota validatefor contract correctness. - Use
ota doctor --jsonwhen you want machine-readable readiness and optional grouped finding summaries with stableaction_keyvalues. - Use
ota check --jsonfor non-executing readiness gates; it carries the same additivefinding_groupsmetadata when present, with the same stableaction_keyshape. - Use
ota annotations --mode doctor --format plainwhen the runner needs portable log lines instead of provider-specific annotation syntax. - Use
ota annotations --mode doctor --format markdownwhen the platform exposes a step-summary or PR-comment surface and ota should own the explanation. - Use
ota receipt --json --archivewhen 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 markdownwhen baseline drift or fail-on-new-blockers gating should explain what changed without custom JSON parsing. - Use
ota workspace doctor --jsonorota workspace check --jsonwhen 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 1fiGitHub 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 --jsonas the feedback surface andreceipt --json --archiveas the durable artifact surface - use
ota annotationswhen the platform supports annotations, markdown summaries, or provider-neutral log rendering - use
--format markdownwhen the platform has a step-summary or PR-comment surface and you want ota’s compact canonical summary block - use
--format plainfor 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@v1withsource: contractwhen the repo already declaresagent.bootstrap.ota.source, otherwise use explicit setup inputs and rely on automaticGITHUB_PATHexport 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@v1when 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 consumeagent.bootstrap.ota.sourcethroughsource: contract - GitHub Actions: use
ota-run/setup@v1withsource: contractwhen later steps need directotacommands and the repo already declaresagent.bootstrap.ota.source; use its explicit inputs when the workflow intentionally chooses the ota version itself - GitLab CI: use
artifacts:when: alwaysso blocked readiness gates still keep.ota/ci/and.ota/receipts/ - Jenkins: archive
.ota/ci/**and.ota/receipts/**inpost { always { ... } } - CircleCI: store
.ota/ciand.ota/receiptsas artifacts before the final fail step