Skip to content

Data Contracts

The Schema watch panel holds the contract controls: Freeze, export, release.

A data contract is the schema your consumers rely on: these tables, these columns, these types, these keys. In Tusk a contract is frozen, not written — you take the schema as it is today and Tusk tells you when reality breaks it.

Contracts sit on top of Schema Watch: every snapshot is evaluated against the connection's active contract.

Freeze a contract

On the Schema page, in the Schema watch panel, click Freeze. Tusk takes a fresh snapshot and stores every table's columns (type, nullability), primary key and foreign keys as the contract. One connection has one active contract; Re-freeze replaces it once you've accepted a change.

From the API you can freeze a subset:

POST /api/contracts/{connection_id}/freeze
{"name": "reporting v2", "tables": ["orders", "customers", "sales.invoices"]}

What breaks a contract

Violation Example summary
Expected table gone customers: table no longer exists
Expected column gone orders.customer_id: column no longer exists
Column type changed orders.id: type integer → bigint
Nullability changed orders.total: NOT NULL added / NOT NULL dropped
Primary key changed orders: primary key ['id'] → ['id', 'region']
Expected foreign key gone orders.customer_id: FK customer_id → customers.id is gone

Additions never break a contract — a new column, table or index is reported by Schema Watch as a change, nothing more.

Being told

Subscribe a channel to Contract Violated (and, if you like, Contract Restored) under Notifications → Subscriptions. A violation is reported once; the same breakage on later runs stays quiet until it either changes or is fixed, at which point you get the restore notice.

The Schema page panel shows the contract state (holds / violated) with the open violation, and agents can ask through the MCP tool contract_status:

"Does production still match the contract? What broke?"

API:

GET    /api/contracts/{connection_id}              # active contract + open violation
GET    /api/contracts/{connection_id}/violations   # history
GET    /api/contracts/{connection_id}/export.yaml  # the contract as YAML
DELETE /api/contracts/{connection_id}              # release it

YAML export

The export is a readable description of the contract, meant for review, version control or sharing with the team that owns the database:

contract: reporting v2
connection_id: 76d39ef4
frozen_at: "2026-09-05T17:10:00+00:00"
tables:
  orders:
    primary_key: [id]
    columns:
      - name: id
        type: integer
        nullable: false
      - name: total
        type: numeric
        nullable: true
    foreign_keys:
      - column: customer_id
        references: customers.id

It is an export, not the source of truth — the frozen snapshot is. Rules that can't be inferred from the catalog (freshness, row-count bounds, uniqueness) are the next layer.

Notes

  • PostgreSQL connections only.
  • Freezing and releasing are audited (contract.freeze, contract.release).
  • Contracts and violations live next to the snapshots in ~/.tusk/schema_watch.db.