# How to use SKMTC in CI/CD



## When to use this [#when-to-use-this]

You want generation to run automatically — either on every PR
(verify the committed output matches what would be regenerated)
or on a schedule (regenerate when the schema changes).

## Prerequisites [#prerequisites]

* A working SKMTC project locally.
* A CI runner that supports Deno installation (most do).

## Steps [#steps]

### Pin the Deno version [#pin-the-deno-version]

Add the Deno version to your CI config so the runtime is
deterministic. For GitHub Actions:

```yaml
- uses: denoland/setup-deno@v1
  with:
    deno-version: v1.46.x   # match your local version
```

### Install the CLI in CI [#install-the-cli-in-ci]

```bash
SKMTC_VERSION=<version> curl -fsSL https://skmtc.dev/install | sh
```

Pin to a specific CLI version with `SKMTC_VERSION`. The CLI itself
doesn't appear in your project's `deno.json` (it's a global
install) — the pin keeps CI runs reproducible.

`--unstable-worker-options` is required: the worker uses Deno's
`Worker.deno.permissions` API, which is gated behind this flag on
current Deno releases. Omitting it produces a runtime error on the
first `skmtc generate` — discovered in CI long after install
"succeeded." The flag must be baked into the installed CLI binary at install time.

### Bundle (if any generators are cloned) [#bundle-if-any-generators-are-cloned]

If the project has cloned or locally-created generators, rebuild
the bundle in CI:

```bash
skmtc bundle <project>
```

If the project is JSR-only (no clones), this step is unnecessary
— the published bundle is used.

### Run with `--no-input --json` [#run-with---no-input---json]

```bash
skmtc generate <project> --no-input --json > generate-output.json
```

The `--no-input` flag enforces strict mode (no interactive
prompts). `--json` produces machine-parseable output for
downstream verification.

Pipe to `jq` for any post-checks you need:

```bash
fails=$(jq '.manifest.parseIssues | map(select(.level == "error")) | length' generate-output.json)
if [ "$fails" -gt 0 ]; then
  echo "Generation produced $fails errors"
  jq '.manifest.parseIssues' generate-output.json
  exit 1
fi
```

### Archive the manifest [#archive-the-manifest]

Upload the `manifest.json` as a CI artifact for retrospective
inspection:

```yaml
- uses: actions/upload-artifact@v4
  with:
    name: skmtc-manifest
    path: .skmtc/<project>/manifest.json
```

Useful when debugging an unexpected generation outcome later.

## Verification [#verification]

Add a "drift check" step that confirms the committed generated
files match what would be regenerated:

```bash
skmtc generate <project> --no-input
git diff --exit-code src/generated/
```

If the diff is non-empty, the committed output is stale — fail
the build and prompt the developer to regenerate.

This check is also where committed generated output pays off in
review: a schema change shows up as an ordinary, readable diff in
the pull request, so your API contract change is reviewed in the
same place as the code that motivated it. Generated code you can't
diff is a black box; this is the opposite.

## Troubleshooting [#troubleshooting]

* **Schema URL unreachable in CI** — The CI environment may have
  network restrictions. Either pin the schema to a local file
  committed in the repo, or use a CI secret for the URL with
  appropriate firewall config.
* **`skmtc generate` times out** — Large schemas (thousands of
  operations) can take a while. Increase the CI timeout or
  partition into multiple smaller projects.
* **Lockfile changes in CI** — If `skmtc install` was run on
  another branch, the lockfile may need updating. Commit
  lockfile changes deliberately, not as part of every generate
  run.
* **"Stale bundle" warning** — Add `skmtc bundle` before `skmtc
  generate` in your CI flow.

## Related [#related]

* [`skmtc generate` reference](/docs/reference/cli/generate)
* [`skmtc bundle` reference](/docs/reference/cli/bundle)
* [`skmtc doctor` reference](/docs/reference/cli/doctor) —
  useful as a CI pre-check
