Wire into CI

OpenSIP CLI is a CLI that exits with a code. The GitHub Action is the shortest

path for pull request feedback; direct CLI commands remain available when you

want to own every baseline and artifact step yourself.

The minimal setup

# .github/workflows/opensip.yml
name: OpenSIP
on: [pull_request, push]

jobs:
  opensip:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: opensip-ai/opensip-cli@v1

For a direct CLI workflow, the recommended public command is:

- run: opensip audit --json

The Action currently invokes the built-in review as `opensip suite run audit

--changed --json` internally. That explicit spelling is an Action implementation

detail, not a different analysis path: both forms use the same built-in suite

executor, Run ledger, review brief, and exit policy. This documentation change

does not change Action inputs or outputs. A supported repository gets

changed-code PR feedback without an opensip-cli.config.yml or an OpenSIP Cloud

account.

Do not add --open in CI. JSON, CI, non-TTY, and remote-shell execution suppress

browser launch. Archive the generated report separately if a human-readable CI

artifact is required; see the report reference.

That's the floor. The rest of this page is the polish: PR comments, SARIF upload,

failure policy, and the lower-level manual baseline flow.

Full GitHub Action setup

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

permissions:
  contents: read
  pull-requests: write
  security-events: write

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

      - uses: opensip-ai/opensip-cli@v1
        id: opensip
        with:
          suite: audit
          changed: true
          annotations: true
          comment: true
          sarif: true
          fail-on: new-errors

      - uses: github/codeql-action/upload-sarif@v4
        if: always() && steps.opensip.outputs.sarif != ''
        with:
          sarif_file: ${{ steps.opensip.outputs.sarif }}
          category: opensip-cli

The action outputs:

| Output | Meaning |

|---|---|

| verdict | pass, warn, or fail from the review brief. |

| issues | Total issue count from the suite aggregate. |

| new-issues | Net-new count when baseline evidence is available. |

| brief | Path to the review brief JSON. |

| sarif | Path to action-generated SARIF when sarif: true. |

| degraded | Comma-separated degraded evidence reasons. |

fail-on: new-errors is the default. It fails on net-new error-rung risks when

baseline evidence is available and falls back to error-rung changed-code risks

when no baseline delta exists. Use fail-on: never for report-only adoption,

all-errors for a hard gate, or new-warnings to include warning-rung new

risks.

The action-generated SARIF is a bounded projection of the audit review brief. For

full source-tool SARIF and persistent baselines, use the manual flow below.

Example artifacts generated by the action renderer:

For regulated or mirror-first environments, pin both moving pieces: the GitHub

Action ref and the npm package version the action runs. The action does not

require an OpenSIP Cloud account; it produces local evidence, annotations, SARIF,

and step outputs from the repository checkout.

PR annotations via SARIF

opensip-cli exports the SARIF format that GitHub understands natively via the fit export --format baseline subcommand. The flow is two steps: run fit --gate-save (which records findings into the project SQLite store, then exits according to the failOnErrors/failOnWarnings thresholds — ADR-0020: the step itself is the gate, not a free pass), then fit export --format baseline --out fit.sarif to write the SARIF document. Uploaded findings appear inline in the PR's "Files changed" view.

- run: opensip fit --gate-save        # record findings, then exit per fail thresholds
- run: opensip fit export --format baseline --out fit.sarif
  if: always()      # the save happened before the exit — export even when the gate failed
- uses: github/codeql-action/upload-sarif@v3
  if: always()      # upload even when a previous step failed
  with:
    sarif_file: fit.sarif
    category: opensip-fit

The if: always() is important — fit --gate-save hard-fails the step when error-level findings breach the configured thresholds (set failOnErrors: 0 in the fitness: block for a ratchet-only adoption where only net-new Code Scanning alerts block PRs), and GitHub skips subsequent steps after a failure by default. The baseline is saved before the exit code is set, so the SARIF export + upload still have everything they need — they just have to actually run.

For GitLab, convert the exported SARIF to the Code Quality widget format with GitLab's converter, renaming the output to gl-code-quality-report.json. (There is no native GitLab code-quality emitter today — go through SARIF.)

Baseline-gate flow

If the codebase already has violations, gating on "all violations" blocks every PR until cleanup is done. Almost no team accepts that. The baseline-gate flow is the alternative: capture today's violations, gate only on new ones.

# Run once locally, on a clean main branch
opensip fit --gate-save
# This writes the baseline into opensip-cli/.runtime/datastore.sqlite

Then in CI:

- run: opensip fit --gate-compare

--gate-compare exits 0 if no new violations appeared since the baseline. Existing ones are tolerated. The baseline lives in SQLite (opensip-cli/.runtime/datastore.sqlite); since .runtime/ is gitignored, you'll want to publish + restore the baseline store as a CI artifact.

The artifact pattern: the gate baseline is a SQLite store, not a committed file. The standard flow is to run fit --gate-save on main-branch builds and upload opensip-cli/.runtime/datastore.sqlite as a workflow artifact; PR builds download that artifact into opensip-cli/.runtime/ before running fit --gate-compare. (For a human-readable export — e.g. to inspect the baseline or feed GitHub Code Scanning — use fit export --format baseline --out baseline.sarif, which reads the same store.) See output, gate, SARIF and the architecture-gate CI patterns for the full workflow.

Recommended full setup

The action setup above is the recommended default. Use the manual shape below

when you need explicit baseline artifact restore/publish behavior.

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

jobs:
  fit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 24 }
      - run: curl -fsSL https://opensip.ai/cli/install.sh | bash

      # Restore the baseline store produced by the last main-branch build.
      - uses: actions/download-artifact@v4
        if: github.event_name == 'pull_request'
        continue-on-error: true
        with:
          name: fit-baseline
          path: opensip-cli/.runtime/

      # On PRs: gate against new violations only.
      # On main: refresh the baseline (so the next PR sees current state).
      - name: Run fit
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            opensip fit --gate-compare
          else
            opensip fit --gate-save
          fi

      # Export the SARIF for PR annotations (reads the SQLite store).
      - name: Export SARIF
        if: always()
        run: opensip fit export --format baseline --out fit.sarif

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: fit.sarif
          category: opensip-fit

      # On main: publish the refreshed baseline store for the next PR.
      - uses: actions/upload-artifact@v4
        if: github.event_name != 'pull_request'
        with:
          name: fit-baseline
          path: opensip-cli/.runtime/datastore.sqlite

This is the shape we recommend: PRs see "is this getting worse?", main updates the bar. Developers fix legacy violations at their own pace; CI is fast (no full-codebase pass on every PR).

Speed

The opensip-cli repository runs a synthetic performance SLO lane in CI:

pnpm bench:slo:ci -- --profile pr --require-memory --out slo-report.json. It

uploads slo-report.json as a workflow artifact with command timings, RSS

measurements, graph profile summaries, and any performance-slo:* signals. The

budgets are documented in Performance SLOs,

and the current published measurements are in

Public benchmarks.

The CI SLO report is clean-wall evidence: the harness removes inherited

profiling and OpenTelemetry export variables. Contributors investigate a

regression locally with pnpm bench:profile, compare repeated before/after

reports with pnpm bench:compare, and use --cpu-profile only as a separate

experiment. The complete workflow and artifact-handling rules are in

Performance profiling.

If fit is slow on a large repo, the usual culprits:

What opensip fit actually does in CI

For a deeper understanding of the gate flow itself — what the baseline contains, how new-vs-old violations are matched, what the exit codes mean — see output, gate, SARIF.

Where to go next

| You want to … | Go to … |

|---|---|

| Adopt incrementally on a large existing codebase | Adopt in a monorepo |

| Coexist with ESLint / migrate gradually | Migrate from ESLint |

| Understand the baseline format and diff logic | Output, gate, SARIF |

| See all CI-relevant CLI flags | CLI commands |