# dbt commands

Send the artifacts dbt writes to target/ to Cassis, from the dbt project's CI: push after a merge to keep the project's dbt baseline current, check on a pull request to see what the change puts in doubt.

Both commands need cassis-cli 3.3. They run in the dbt project’s repository, which has no `cassis/project.yml`, so set `CASSIS_PROJECT_ID` or pass `--project`. The workflow is in [Handle source changes](/curate/data-source-changes/#when-a-dbt-model-changes); the CI jobs are [below](#ci-setup).

## dbt push

Uploads `manifest.json`, and `catalog.json` when present, as the project’s new dbt baseline. Run it after `dbt docs generate` on your production target, after a merge to the production branch.

```bash
dbt docs generate --target prod
cassis dbt push target --project ...
```

It waits for Cassis to check the files, then prints how many dbt models and sources match tables of the project’s data source and how many tests they declare. Cassis compares the upload with the previous baseline and files each part of the context the change puts in doubt as an issue with the `at_risk` impact. The command lists those issues with their reach and a link to each.

## dbt check

Uploads a pull request’s artifacts as a check. Run it after `dbt compile` (or `dbt docs generate`) on the production target.

```bash
dbt compile --target prod
cassis dbt check target --project ...
```

Cassis compares the artifacts with the project’s dbt baseline and the command prints the context tables, columns, joins, and metrics the change puts in doubt, grouped by context object, each with why it matters and the context change to make. Then it prints the tables and columns dbt no longer builds. A removed model names the joins, metrics, and virtual tables that use it, and a column that disappears while exactly one appears is reported as likely renamed. Within each section, the objects with the widest reach print first. Nothing is filed and the baseline does not move.

## Options

Both commands take the same options.

- **Target** The positional argument is dbt’s target directory, `target` by default. `manifest.json` is required; `catalog.json` is sent when present.

- **Commit** `--commit` (default: `HEAD` of the git checkout) and `--commit-message` (default: read from git). Outside a git checkout, `--commit` is required.

- **Pull request** `--pr-title` and `--pr-description`. On GitLab CI and GitHub Actions they default to the merge request or pull request. After a merge, `push` finds the title of the pull request that merged the commit: on GitHub Actions through the GitHub API (expose `GITHUB_TOKEN` to the step; a failure is ignored), on GitLab from the merge commit.

- **Waiting** `--poll-interval` (2 seconds) and `--timeout` (10 minutes).

- **Links** `--app-url` or `CASSIS_APP_URL` sets the web app’s address for the links to filed issues, when it is not served from the API host.

- **JSON** `--json` prints the upload record on stdout; the summary goes to stderr.

- **Size** Up to 128 MB per file, and 32 MB once compressed. An oversized file fails before anything is sent.

## Exit codes

| Code | dbt push | dbt check |
| --- | --- | --- |
| 0 | Accepted as the baseline, or kept behind a newer upload | Checked, with or without findings |
| 1 | Rejected: an invalid file, an unsupported dbt version, or no relation matches the project’s data source | Rejected: an invalid file, or no baseline yet (run `dbt push` on the production branch first) |
| 2 | Usage error: no `manifest.json`, no commit, or a file over the size limit | Same |
| 3 | Transport error, or Cassis failed while processing the upload: push again | Same |

`dbt check` never fails your CI on findings. Gate on exit codes 1 to 3 only.

## CI setup

Both jobs run in the dbt project’s repository. Store `CASSIS_API_KEY` as a secret and `CASSIS_PROJECT_ID` as a variable. The key needs edit access to the project; [scope it](/setup/api-keys/) to that project. The dbt steps run on your production target, so the job needs the same dbt setup and warehouse credentials as your other dbt jobs.

### GitHub Actions

```yaml title=".github/workflows/cassis-dbt.yml"
name: Cassis dbt

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read
  pull-requests: read

jobs:
  cassis-dbt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      # Install dbt and its adapter, and configure the profile, as in your other dbt jobs.
      - run: python -m pip install "cassis-cli~=3.3"
      - if: github.event_name == 'push'
        run: |
          dbt docs generate --target prod
          cassis dbt push target
        env:
          CASSIS_API_KEY: ${{ secrets.CASSIS_API_KEY }}
          CASSIS_PROJECT_ID: ${{ vars.CASSIS_PROJECT_ID }}
          GITHUB_TOKEN: ${{ github.token }}
      - if: github.event_name == 'pull_request'
        run: |
          dbt compile --target prod
          cassis dbt check target
        env:
          CASSIS_API_KEY: ${{ secrets.CASSIS_API_KEY }}
          CASSIS_PROJECT_ID: ${{ vars.CASSIS_PROJECT_ID }}
```

`GITHUB_TOKEN` lets the push find the pull request that merged the commit, so the issues it files carry the pull request’s title. Change `main` if your production branch has another name.

### GitLab CI

```yaml title=".gitlab-ci.yml"
cassis-dbt-push:
  image: python:3.12  # not -slim: the CLI reads the commit from git
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  script:
    # Install dbt and its adapter, and configure the profile, as in your other dbt jobs.
    - python -m pip install "cassis-cli~=3.3"
    - dbt docs generate --target prod
    - cassis dbt push target

cassis-dbt-check:
  image: python:3.12
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - python -m pip install "cassis-cli~=3.3"
    - dbt compile --target prod
    - cassis dbt check target
```

On GitLab the push reads the merge request’s title from the merge commit.
