| name | data-contract-author |
| description | Scaffolds and validates ODCS v3.1.0 data contracts using datacontract-cli. Use when the
user asks to create, write, scaffold, or author a data contract, generate an ODCS file,
define a contract for a table or model, or mentions ODCS, datacontract-cli, logicalType,
dimension, data product contract, or schema contract. Also trigger for: "new contract",
"add contract", "contract for a model", "lint contract", or questions about valid
logicalType and dimension enum values. Do not use for general dbt model schema
documentation unrelated to contracts, SQL quality checks outside of a contract context,
or PySpark/Spark pipeline code.
|
| allowed-tools | Read Write Edit Bash |
| license | GPL-3.0-only |
| status | unstable |
| metadata | {"author":"Leandro Kellermann de Oliveira <lkellermann@leandroasaservice.com>","version":"0.1.0","model":"sonnet"} |
Data Contract Author
Scaffolds ODCS v3.1.0 data contracts and validates them with datacontract-cli. This skill produces complete, lint-passing YAML contract files for any data table or mart model.
Precondition: datacontract-cli must be installed and runnable via uv run datacontract lint. If it is not available, stop and tell the user before proceeding. Installation: uv add datacontract-cli or pip install datacontract-cli.
Runtime Context — Infer or Ask First
Before generating a contract, determine the following values. Infer them from context (open files, project structure, previous conversation) or ask the user if they cannot be determined:
| Value | How to get it |
|---|
model_name | From the user's request, a file path, or ask |
server.type | Database technology (bigquery, snowflake, postgres, etc.) — infer from project config or ask |
server.project / server.dataset (BigQuery) or equivalent connection fields | From project config, .env, or ask |
domain / tenant | From project context or ask |
team.id, team.name, team.members | From project metadata or ask |
contract id | Compose as <platform>.<project>.<dataset>.<model_name> using the values above |
Never hardcode platform-specific values (GCP project IDs, dataset names, team names). Each contract must reflect its actual deployment context.
Workflow
Step 1 — Discover the model schema
If a dbt schema.yml or equivalent schema file exists, read it and find the entry for model_name. Extract:
- Model description
- All column names, descriptions, and tests (
not_null, unique, relationships, accepted_values)
If no schema file exists, ask the user to describe the model's columns, types, and intent before generating the contract.
Step 2 — Generate the contract file
Read references/ODCS_TEMPLATE.md for the annotated YAML template before writing any YAML.
Create contracts/<model_name>.yaml (or a path specified by the user). Apply these rules exactly — deviations will fail datacontract lint:
Valid logicalType values: string, date, timestamp, time, number, integer, object, array, boolean
- Use
number for floats/decimals, NOT numeric
- The table-level entry always uses
logicalType: object and physicalType: table
Valid dimension values for quality checks: accuracy, completeness, conformity, consistency, coverage, timeliness, uniqueness
- Use
conformity for range/accepted-value checks, NOT validity
Structural rules:
schema is a direct YAML array — no wrapping objects: key
- Quality checks belong inside
schema objects and properties, NOT at the top level
- Always use
type: sql for quality checks — type: library causes a NoneType crash in datacontract test
- SQL queries must use fully-qualified table references
team uses the modern single-object format with a members array (see template)
- Column
description values must be quoted single-line strings, never YAML block scalars (|)
Deriving field values from schema.yml:
required: true if the column has a not_null test
primaryKey: true if the column has a unique test on that column
- Add a completeness quality check on the primary key column and any column with
accepted_values tests
businessName is a human-readable version of the column name (e.g., order_id → "Order ID")
Step 3 — Lint the contract
Run:
uv run datacontract lint contracts/<model_name>.yaml
Fix all reported errors before proceeding to Step 4.
Step 4 — Confirm and remind the user
After the file passes lint, report:
- The file path created and that it passed
datacontract lint
- Fields that need manual completion:
limitations, any businessName that requires domain knowledge
- That
status should be changed from draft to active when the contract is formally agreed with consumers
- That
slaProperties values are placeholders and should reflect real commitments once the serving layer is live
Examples
Example 1: BigQuery mart model with dbt schema file
User says: "Create a data contract for the fct_orders model."
Actions:
- Read
dbt/models/marts/schema.yml, locate fct_orders entry
- Ask for BigQuery project/dataset if not found in project config
- Read
references/ODCS_TEMPLATE.md
- Create
contracts/fct_orders.yaml with all columns, quality checks, and server config
- Run
uv run datacontract lint contracts/fct_orders.yaml
- Fix any lint errors, then report result
Result: contracts/fct_orders.yaml created and passing lint, with a summary of fields to complete.
Example 2: No existing schema file, Snowflake target
User says: "I need an ODCS contract for a dim_customers table in Snowflake."
Actions:
- Ask: column names and types, primary key, Snowflake account/database/schema, domain, team info
- Read
references/ODCS_TEMPLATE.md
- Generate contract with all provided/inferred values, adapting
servers block for Snowflake
- Run
uv run datacontract lint contracts/dim_customers.yaml
- Fix errors, report result
Result: contracts/dim_customers.yaml created and passing lint.
Error Handling
If uv run datacontract lint is not available (command not found), stop immediately and tell the user to install datacontract-cli before proceeding.
If datacontract lint reports errors, apply these fixes:
| Error message | Cause | Fix |
|---|
Unknown logicalType | Invalid type value | Replace with a value from the valid list: string, date, timestamp, time, number, integer, object, array, boolean |
dimension ... not valid | Unsupported dimension | Replace validity with conformity, or use another value from the valid set |
NoneType has no attribute get | type: library quality check | Change all quality check type: values to sql |
Expected string, got block scalar | Block scalar in a string field | Change description: followed by a block scalar to a quoted single-line string |
schema requires array | objects: wrapper present | Remove the objects: key; schema must be a direct array |
mustBe must be a number | mustBe is a quoted string | Remove quotes: mustBe: 0 not mustBe: "0" |