kolm  /  tutorials  /  CI verify

Sign and verify in CI.

Set up GitHub Actions to compile, sign, and verify every model artifact your team produces. The verifier blocks the PR if K-score regresses. The receipt is posted as a PR comment auditors can read.

Runtime 11 minRunner ubuntu-22.04Verifier open-sourceSecret needed KOLM_API_KEY

Step 1 . 60 seconds

Add a repository secret.

GitHub repo → Settings → Secrets and variables → Actions → New repository secret. Name it `KOLM_API_KEY`. Paste your key from kolm.ai/account.

Step 2 . 4 minutes

Drop in the workflow.

Create `.github/workflows/kolm-verify.yml` with the snippet below.

name: kolm verify

on:
  pull_request:
    paths:
      - 'recipes/**'
      - '.github/workflows/kolm-verify.yml'

jobs:
  verify:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm install -g kolm
      - run: kolm version

      # compile every recipe touched by this PR
      - name: compile + sign
        env:
          KOLM_API_KEY: ${{ secrets.KOLM_API_KEY }}
        run: |
          for recipe in recipes/*.recipe.json; do
            kolm compile --from "$recipe" --out "artifacts/$(basename $recipe .recipe.json).kolm"
          done

      # verify every artifact (works offline)
      - name: verify
        run: |
          for art in artifacts/*.kolm; do
            kolm verify "$art" --binder "artifacts/$(basename $art .kolm).binder.pdf"
          done

      # post receipts as PR comment
      - name: post receipts
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const receipts = fs.readdirSync('artifacts').filter(f => f.endsWith('.receipt.json'));
            const body = receipts.map(r => {
              const j = JSON.parse(fs.readFileSync(`artifacts/${r}`));
              return `**${r}** . K=${j.k_score} . CID \`${j.cid}\``;
            }).join('\n');
            await github.rest.issues.createComment({
              ...context.repo, issue_number: context.issue.number, body,
            });

Step 3 . 60 seconds

Add a K-score floor.

Set a K-score floor in the recipe so the compile step fails the CI run if quality regresses.

{
  "task": "redact PHI from clinical notes",
  "base": "qwen2.5-7b-instruct",
  "target_k": 0.95,
  "min_k": 0.92,
  "eval_pack": "hipaa-redact-v1"
}
Checkpointmin_k is the floor. The compile step exits non-zero if K-score is below it. CI fails. PR is blocked.

Step 4 . 60 seconds

Push a recipe change.

Open a PR that changes one recipe. The CI run compiles, verifies, and comments. You will see something like this in the PR conversation.

[bot] kolm verify

**phi-redactor.receipt.json** . K=0.982 . CID `cidv1:sha256:1bcf2323...`
**triage.receipt.json** . K=0.961 . CID `cidv1:sha256:8a3d1c4e...`

✓ all artifacts verified

Step 5 . optional

Pin artifacts in release.

On merge, upload artifacts and receipts to your release. The CID is the immutable handle for an audit five years from now.

- name: release
  if: github.event_name == 'release'
  uses: softprops/action-gh-release@v2
  with:
    files: |
      artifacts/*.kolm
      artifacts/*.receipt.json
      artifacts/*.binder.pdf