Axiomatic
Guides

CI/CD Integration

Using the Official Action

The easiest way to run Axiomatic in CI is with the official GitHub Action. It runs your tests, posts a summary comment on the PR, and outputs GitHub annotations on the diff -- all without needing an Axiomatic account.

# .github/workflows/axiomatic.yml
name: Axiomatic

on:
  pull_request:
    branches: [main]

permissions:
  pull-requests: write

jobs:
  axiomatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: exalto-ai/axiomatic@v1
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}

The Action handles everything: installs the CLI, runs tests, posts a PR comment with a results table, and sets the correct exit code. No platform login or GitHub App required.

Action Inputs

InputDescriptionDefault
anthropic-api-keyAnthropic API key--
openai-api-keyOpenAI API key--
argsExtra arguments passed to axm run""
commentPost a summary comment on the PR"true"
tokenGitHub token for PR commentsGITHUB_TOKEN
platform-tokenAxiomatic platform token for dashboard sync (optional)--

With Caching

Add result caching to reduce costs and speed up runs:

# .github/workflows/axiomatic.yml
name: Axiomatic

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

permissions:
  pull-requests: write

jobs:
  axiomatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/cache@v4
        with:
          path: .axiomatic/cache.db
          key: axiomatic-${{ hashFiles('axiomatic/**/*.yml') }}-${{ github.sha }}
          restore-keys: |
            axiomatic-${{ hashFiles('axiomatic/**/*.yml') }}-
            axiomatic-

      - uses: exalto-ai/axiomatic@v1
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          args: "--bail"

Running Only Security Tests on PRs

Use args to filter by tag:

      - uses: exalto-ai/axiomatic@v1
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          args: "--tag security --bail"

With Dashboard Sync

To optionally send results to the Axiomatic dashboard for history and trend tracking, add your platform token:

      - uses: exalto-ai/axiomatic@v1
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          platform-token: ${{ secrets.AXM_PLATFORM_TOKEN }}

Manual Setup (Without the Action)

If you prefer not to use the composite action, you can set up the workflow manually:

# .github/workflows/axiomatic.yml
name: Axiomatic

on:
  pull_request:
    branches: [main]

permissions:
  pull-requests: write

jobs:
  axiomatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - run: npm install -g @exalto/axiomatic

      - name: Validate test files
        run: axm validate

      - name: Run Axiomatic tests
        run: axm run --format github --bail
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

The --format github flag outputs results as GitHub Actions annotations, so violations appear inline on the PR diff.

To add a PR comment with the manual approach, use a sticky comment action:

      - name: Run Axiomatic tests
        id: axiomatic
        run: |
          axm run --format github 2>&1 | tee axiomatic-output.txt
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Comment on PR
        if: always() && github.event_name == 'pull_request'
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          path: axiomatic-output.txt

GitLab CI

# .gitlab-ci.yml
axiomatic:
  stage: test
  image: node:22
  variables:
    ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
  cache:
    key: axiomatic-$CI_COMMIT_REF_SLUG
    paths:
      - .axiomatic/cache.db
  before_script:
    - npm install -g @exalto/axiomatic
  script:
    - axm validate
    - axm run --bail
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

CircleCI

# .circleci/config.yml
version: 2.1

jobs:
  axiomatic:
    docker:
      - image: cimg/node:22.0
    steps:
      - checkout
      - restore_cache:
          keys:
            - axiomatic-{{ checksum "axiomatic.yml" }}
            - axiomatic-
      - run:
          name: Install Axiomatic
          command: npm install -g @exalto/axiomatic
      - run:
          name: Run Axiomatic tests
          command: axm run --bail
          environment:
            ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
      - save_cache:
          key: axiomatic-{{ checksum "axiomatic.yml" }}
          paths:
            - .axiomatic/cache.db

workflows:
  test:
    jobs:
      - axiomatic

Jenkins

// Jenkinsfile
pipeline {
    agent any

    environment {
        ANTHROPIC_API_KEY = credentials('anthropic-api-key')
    }

    stages {
        stage('Axiomatic') {
            steps {
                sh 'npm install -g @exalto/axiomatic'
                sh 'axm validate'
                sh 'axm run --bail'
            }
        }
    }
}

Exit Codes

All CI integrations can rely on Axiomatic's exit codes:

CodeMeaningCI behavior
0All tests passedPipeline passes
1One or more tests failedPipeline fails
2Configuration error or provider failurePipeline fails

Exit code 1 is returned when any test has a fail status, regardless of severity. Exit code 2 indicates a configuration or provider error.

Best Practices

Cache test results between runs. This is the single most impactful optimization. Caching means unchanged tests are served at zero cost, and CI runs complete faster.

Use --bail in CI. Stop on the first failure rather than spending API credits on remaining tests when the build will fail anyway.

Use --format github for GitHub Actions. Violations appear as inline annotations on the PR diff, making them impossible to miss.

Run axm validate before axm run. Validate catches YAML errors and missing fields without making API calls. Fail fast on configuration issues.

Use tags for conditional execution. Run --tag security on every PR, but --tag architecture only on nightly builds or main branch pushes.

Set concurrency limits. Use --parallel to control how many tests run concurrently. Lower values reduce peak API usage; higher values reduce wall-clock time.

Dry-run for cost estimation. Use axm run --dry-run to estimate costs before committing to a full run in a new environment.

On this page