Skip to content
Raw Markdown

Schema commands

Four commands about the warehouse layer beneath the context: pull a local snapshot to work from, then plan, apply and push a schema update so the context follows the source without anything landing unreviewed.

schema pull

Downloads the project’s full source schema, as last introspected from the warehouse or uploaded as DDL, into cassis/.schema.json.

# In a checkout with cassis/project.yml, the project id is read from it
cassis schema pull

# Or name the project and checkout explicitly
cassis schema pull /path/to/checkout --project 019f0000-0000-7000-8000-000000000000

This is the bulk counterpart to the MCP server’s get_source_schema tool: instead of paging through 20 tables per call, an agent on a modeling pass greps one local file.

Observed state, not truth
The snapshot is stamped with pulled_at. The warehouse stays authoritative and the file is a local cache. Re-run to refresh.
Never committed
The command maintains a .gitignore entry for it in the context directory.
Exit codes
0 on success, 2 on a usage error including a checkout it cannot write to, 3 on a transport or API error.

The plan is the contract

plan, apply and push share one model. Cassis diffs the new schema against the stored one and derives the context edits it implies: every change on a table that is in the context (placed in a domain), with everything a drop takes with it (joins, metrics, virtual tables). Tables outside the context only move the schema. The plan is shown before anything is written, and push applies exactly what it lists. It is the same plan the web app shows for Update from DDL and Sync from warehouse, described in Review schema updates.

The new schema comes from one of two places, and the flag decides which:

A DDL file
cassis schema plan schema.sql. The file speaks only for the schemas it contains: a per-schema export adds and updates those schemas and leaves the rest of the source as it was. Pass --complete when the file is the whole source schema, so a schema absent from it counts as dropped.
The connected warehouse
cassis schema plan --warehouse. Cassis introspects the project’s warehouse server-side, so a CI job can bring the context up to date the moment a migration merges rather than waiting for the nightly plan. A warehouse plan is always whole-source.

Needs cassis-cli 2.0.0 or newer. Like the other project-bound commands, the project id comes from cassis/project.yml in the checkout, CASSIS_PROJECT_ID, or --project, and --path points at a checkout other than the current directory.

schema plan

Previews what a schema update would change. Nothing is applied.

# Preview a DDL update
cassis schema plan schema.sql

# The file is the whole source schema: schemas missing from it were dropped
cassis schema plan schema.sql --complete

# Warehouse-connected project: introspect instead of parsing a file
cassis schema plan --warehouse

# Machine-readable: the plan record on stdout, or written to a file
cassis schema plan schema.sql --json
cassis schema plan schema.sql --out plan.json
What it prints
Terraform-style: the schema diff (tables and columns added, changed, removed), source metadata changes with their before and after values, the context changes the update implies (renames carried over, dropped columns with the joins and metrics that reference them, tables that leave the context), and warnings, such as a placed table about to lose its description.
Incomplete extraction
Unsupported or malformed objects appear as structured diagnostics with their location. Cassis also prints the inventory it did extract, then exits 1. The plan is kept for inspection but cannot be applied or pushed; resolve the errors and create a new plan.
Suspected truncation
A file that drops most of the tracked tables in a schema it does cover, or that stops part-way through a statement, fails the plan rather than producing a plan full of removals. Exit 1 with the reason.
One plan per project
A plan that reaches ready replaces the project’s previous plan, including the one the nightly warehouse sweep left waiting. Only a plan being applied blocks a new one, which plan reports as exit 1.
Machine-readable output
--json prints the plan record on stdout and moves the rendering to stderr, so piping into jq works. --out writes the same record to a file and keeps the rendering on the terminal.
Waiting
The plan is computed server-side. --poll-interval (5 seconds) and --timeout (30 minutes) control the polling; on a timeout the plan keeps computing and exit is 3.
Exit codes
0 when the plan is ready, an empty plan included. 1 when the plan failed: unparseable or truncated DDL, an unreachable warehouse, a plan already being applied. 2 on a usage error, 3 on a transport or API error, or a timeout.

schema apply

Plans, then writes the resulting context files into the local checkout. The app is not modified.

# Plan a DDL update and write the context it produces under cassis/
cassis schema apply schema.sql

# From the connected warehouse
cassis schema apply --warehouse

# Write a plan that is already ready, for instance after a timeout or from the nightly sweep
cassis schema apply --plan 019f0000-0000-7000-8000-0000000000a1
GitOps
This is the review step for a git-managed context: renamed tables, dropped columns, and rewritten joins and metrics land as file changes you read with git diff, edit if the plan did not know something, and commit. Send the result with schema push.
Stale files
Context files the plan makes obsolete (a dropped table, a join with nothing left to join) are deleted when git can restore them.
Local edits
apply refuses to write over a local context that differs from the app’s, so uncommitted work is not overwritten by accident. --force writes anyway.
Exit codes
0 when written. 1 when the plan failed, is stale, or has incomplete extraction. 2 on a usage error, 3 on a transport or API error.

schema push

Pushes the new schema and the local context to the app, in that order.

# Plan, apply server-side, then upload the local context; --yes skips the prompt
cassis schema push schema.sql --yes

# Warehouse-connected project, from CI
cassis schema push --warehouse --yes

# Publish the result as a new version
cassis schema push schema.sql --yes --publish --label "Schema 2026-09"
Two steps
The schema update is planned and applied server-side (new schema version stored, tracked schema updated, the context edits the plan lists), then the local context tree replaces the project’s unpublished context, so hand edits made after schema apply land too. --publish publishes it as a new version, --label names it.
Committed files only
Like context upload, it runs from a git checkout whose context files match HEAD, and a published version records that commit. Commit what schema apply wrote, and any hand edits, before pushing. An uncommitted context file, a directory outside git, or a machine without git stops it with exit 2 before anything is planned or sent. Needs cassis-cli 3.0.0 or newer.
Confirmation
The plan is shown and the command asks before pushing. --yes (-y) skips the prompt and is required without a TTY, so a CI job has to pass it.
Stale plans
A plan whose schema or context moved between plan and push is refused: exit 1 with Schema plan is stale. Plan again; the new plan replaces the old one.
What success prints
The schema version stored and the number of context changes applied, then the upload result.
Exit codes
0 when pushed. 1 when the plan failed, is stale, has incomplete extraction, or the context upload was rejected. 2 on a usage error, uncommitted context files included, 3 on a transport or API error.

A DDL file speaks only for the schemas it contains. Without --complete, a schema missing from the file is left as it was. If a pipeline of yours signals a dropped schema by leaving it out of the file, pass --complete or those drops are not planned. The scoping lives in Cassis, so it applies to the web app’s upload as well.

From CI

Preview on merge requests, push on the default branch. The plan job fails on a DDL that does not parse, so a broken export never reaches the context.

schema-plan:
  image: python:3.12-slim
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes: [schema/**/*]
  script:
    - python -m pip install "cassis-cli~=3.1"
    - cassis schema plan schema/schema.sql
  variables:
    CASSIS_API_KEY: $CASSIS_API_KEY
    CASSIS_PROJECT_ID: $CASSIS_PROJECT_ID

schema-push:
  image: python:3.12  # not -slim: the push needs git
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes: [schema/**/*]
  script:
    - python -m pip install "cassis-cli~=3.1"
    - cassis schema push schema/schema.sql --yes
  variables:
    CASSIS_API_KEY: $CASSIS_API_KEY
    CASSIS_PROJECT_ID: $CASSIS_PROJECT_ID

The push job uses the full python image because schema push needs git from cassis-cli 3.0.0, and the -slim image lacks it. On a warehouse-connected project, run cassis schema push --warehouse --yes from the pipeline that deploys your migrations, in a checkout of the context repository, and the context follows the source the same hour. The GitHub Actions equivalent follows the publish workflow, with cassis schema push in place of cassis context upload.

schema pull writes a local snapshot and changes nothing. plan changes nothing either. apply changes files in your checkout, and push is the only command that writes to the app. cassis status shows the plan currently waiting on a project.