CI/CD Integration

Gate your PRs on semantic proofs, not just green tests.

Overview

Tests prove that code runs. aura prove proves that code does the thing you said it would do. aura pr-review proves that the code change matches its stated intent. Running both in CI raises your merge gate from "tests pass" to "tests pass and the change is semantically consistent with its intent."

Aura runs in any CI:

This page covers generic CI patterns: exit codes, caching, containerization, and how to make Aura a hard gate without slowing the pipeline.

Setup

Binary distribution

A single static binary. Install in any Linux/macOS container:

curl -fsSL https://aura.build/install.sh | sh

Or pin a version:

curl -fsSL https://aura.build/install.sh | sh -s -- --version 0.14.1

Or use the official image:

ghcr.io/naridon-inc/aura:0.14.1
ghcr.io/naridon-inc/aura:latest

The image is ~40 MB, Alpine-based, and contains aura + git. It is designed as a CI image, not a dev image.

Shadow branches

CI needs shadow branches to compute semantic diffs. Fetch them before running Aura:

git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*'

If shadow branches don't exist yet, aura prove degrades gracefully — it computes what it can from the current working tree and warns about missing history.

Exit Codes

Every Aura CI-relevant command returns deterministic exit codes so pipelines can branch on them.

aura prove

| Code | Meaning | Typical action | |------|---------|----------------| | 0 | All goals proved. | Pass. | | 1 | Some goals failed. | Fail the build. | | 2 | No goals logged for this branch. | Warn or pass (configurable). | | 3 | Engine error (missing shadow, corrupt index). | Fail with alert to platform team. | | 4 | Timeout. | Retry once, then fail. |

aura pr-review

| Code | Meaning | |------|---------| | 0 | No violations at or above fail_on threshold. | | 1 | Violations found. | | 2 | Intent not logged. | | 3 | Engine error. |

aura doctor

| Code | Meaning | |------|---------| | 0 | Healthy. | | 1 | Warnings (missing hooks, stale snapshots). | | 2 | Errors (corrupt DB, orphaned sessions). |

Exit codes are stable across versions. CI scripts can rely on them.

Configuration

CircleCI

.circleci/config.yml:

version: 2.1

jobs:
  aura:
    docker:
      - image: ghcr.io/naridon-inc/aura:latest
    steps:
      - checkout
      - run:
          name: Fetch shadow branches
          command: git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*'
      - run:
          name: aura prove
          command: aura prove --base origin/main
      - run:
          name: aura pr-review
          command: aura pr-review --base origin/main --format markdown --output review.md
      - store_artifacts:
          path: review.md

workflows:
  review:
    jobs:
      - aura:
          filters:
            branches:
              ignore: main

Jenkins

pipeline {
  agent {
    docker { image 'ghcr.io/naridon-inc/aura:latest' }
  }
  stages {
    stage('Shadow') {
      steps {
        sh "git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*'"
      }
    }
    stage('Prove') {
      steps {
        sh 'aura prove --base origin/main'
      }
    }
    stage('Review') {
      steps {
        sh 'aura pr-review --base origin/main --format markdown --output review.md'
        archiveArtifacts artifacts: 'review.md'
      }
    }
  }
  post {
    failure {
      script {
        def review = readFile 'review.md'
        // Post to Slack / PR / etc.
      }
    }
  }
}

Buildkite

steps:
  - label: "aura"
    command:
      - git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*'
      - aura prove --base origin/$BUILDKITE_PULL_REQUEST_BASE_BRANCH
      - aura pr-review --base origin/$BUILDKITE_PULL_REQUEST_BASE_BRANCH
    plugins:
      - docker#v5.0.0:
          image: "ghcr.io/naridon-inc/aura:latest"
    if: build.pull_request.id != null

Azure Pipelines

steps:
  - task: Docker@2
    inputs:
      command: run
      arguments: >
        -v $(Build.SourcesDirectory):/src -w /src
        ghcr.io/naridon-inc/aura:latest
        sh -c "git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*' &&
               aura prove --base origin/$(System.PullRequest.TargetBranch) &&
               aura pr-review --base origin/$(System.PullRequest.TargetBranch)"

Caching

Aura's AST index is deterministic given the commit SHA. Cache it between pipeline runs for a 5–10x speedup on large repos:

# GitHub Actions example, reusable pattern
- uses: actions/cache@v4
  with:
    path: .aura/index
    key: aura-index-${{ hashFiles('**/*.rs', '**/*.ts', '**/*.py') }}
    restore-keys: aura-index-

Cache keys should include every source-file extension Aura indexes. The cache is invalidated on any source change, which is correct — the index must match the tree.

Examples

Hard gate

Fail the build if aura prove fails or if PR review finds error-level violations. This is the recommended baseline:

aura prove --base origin/main  || exit 1
aura pr-review --base origin/main --fail-on error || exit 1

Soft gate (advisory mode)

For teams rolling out Aura incrementally:

aura prove --base origin/main  || echo "::warning::aura prove failed (advisory)"
aura pr-review --base origin/main --fail-on never

This runs the checks and posts the report, but never fails the build.

Parallel pipelines

aura prove and aura pr-review share an AST parse step. Run them in the same job to reuse it. If you must split them across jobs, share the cached index:

# Job 1
aura index --output .aura/index.bin
# Job 2 (depends on Job 1)
aura prove --index .aura/index.bin
# Job 3 (depends on Job 1)
aura pr-review --index .aura/index.bin

Gating on a specific goal

aura prove "Checkout flow redirects to success page on completed payment"

Useful for "I care about this one behavior this PR must preserve" gates. Multiple --goal flags are allowed.

Intent-required enforcement

Reject PRs that never called aura_log_intent:

aura pr-review --require-intent --fail-on error

Exit code 2 is returned if no intent exists; turn it into a failure with --require-intent.

Troubleshooting

Pipeline is slow. Enable caching of .aura/index. Expect 30s–2m parse time without cache on mid-sized (~100K LOC) repos; <10s with cache.

aura prove returns 2 for every PR. No intents are being logged. The pre-commit hook isn't firing locally. See pre-commit hook. As an interim, enable --require-intent only for main merges, not every PR.

Shadow branch fetch fails. The CI bot user lacks read access to aura/* refs. Either widen the token scope or push shadow branches to a mirror repo.

Different results on CI vs local. Almost always a version mismatch. Pin aura in CI (--version 0.14.1) and locally.

Timeouts on very large repos. Set AURA_PARSE_TIMEOUT=300 (seconds) and consider partitioning: aura prove --scope apps/web. Aura supports scope-restricted runs that parse only a subtree.

Running Aura in Matrix Jobs

If your CI runs a matrix (multiple OSes, multiple language versions), avoid running Aura once per matrix cell. Semantic analysis is platform-independent — running it N times wastes N-1 runs and risks races on shadow-branch pushes. Run Aura in a single dedicated job, gated on the matrix jobs' success:

jobs:
  test:
    strategy:
      matrix: { os: [ubuntu-latest, macos-latest, windows-latest] }
    steps: [ ... your tests ... ]

  aura:
    needs: test
    runs-on: ubuntu-latest
    steps: [ ... aura commands ... ]

This pattern keeps the semantic gate deterministic and fast.

Reporting and Metrics in CI

Every aura prove and aura pr-review run emits a machine-readable summary to .aura/ci-summary.json. Archive it as an artifact to build dashboards:

{
  "run_id": "run_01HW3K...",
  "branch": "feat/login",
  "base": "main",
  "timestamp": "2026-04-21T14:23:09Z",
  "prove": { "goals": 4, "passed": 4, "failed": 0, "duration_ms": 1823 },
  "review": {
    "findings": { "error": 0, "warning": 2, "info": 5 },
    "nodes_changed": 12,
    "duration_ms": 2410
  }
}

Feed this into your observability stack (Datadog, Grafana) to track CI-side semantic health over time: average Prove duration, error-finding rate per team, node churn.

Authoring a Minimal CI Wrapper

If your CI isn't covered above, the generic pattern is three commands:

git fetch origin '+refs/heads/aura/*:refs/remotes/origin/aura/*'
aura prove --base origin/main
aura pr-review --base origin/main --format markdown --output review.md

Whatever CI you are on, reproduce those three lines in its syntax. Every other integration detail — annotations, artifacts, merge gates — is a nice-to-have on top of this minimum.

Self-Hosted Runners

For self-hosted GitHub Actions or GitLab runners, pre-install Aura in the base AMI/image. This saves the install step on every job and makes the runner's version stable. The official image ghcr.io/naridon-inc/aura is built reproducibly and has SBOM attestations published to the same registry.

If your org policy forbids pulling images from public registries, mirror the release tarball internally:

curl -fsSLO https://aura.build/releases/0.14.1/aura-x86_64-linux.tar.gz
sha256sum -c aura-x86_64-linux.tar.gz.sha256

All releases are published with Sigstore-signed SHA256 manifests.

Security Considerations in CI

A few practices worth enforcing:

  • Scope the CI token. AURA_TOKEN in CI should have read_intents, write_impacts, and read_snapshots — nothing broader. Avoid giving CI write_messages unless you intentionally want CI to post into team chats.
  • Redact in logs. Set AURA_LOG_REDACT=true to strip sensitive fields from daemon logs written to CI artifacts.
  • Don't cache secrets in .aura/. The cache directory is for the AST index only. Aura never writes tokens there, but a misconfigured hook could; a .gitignore entry of .aura/secrets* belongs in every repo.

Monorepo Strategies

Large monorepos benefit from two patterns:

  1. Scoped Prove runs. Run aura prove --scope apps/web in each app's pipeline rather than one mega-run. Each team owns its Prove goals and sees only its failures.
  2. Shared index cache. One cache key per language — aura-index-rust-${hashFiles('**/*.rs')} — so the Rust app's cache doesn't invalidate when TS changes.

See Also