CLI quickstart — zero to first contract
This page walks you top to bottom: bootstrap a project, scaffold a
contract, validate it, apply it to your Databricks workspace, and
read the audit line the run leaves behind. It assumes you have
installed the CLI and that
kiri databricks health passes against your target.
Bootstrap the project — kiri init
kiri init acme-dw --silver-technique data_vault --adapter databricks
cd acme-dw
kiri init is deliberately fail-closed. It refuses to guess the
decisions that are expensive to change later:
--silver-techniqueis required —flat,data_vault, orkimball_dimensional. It is locked after your first silver contract; changing it later means a migration, so the CLI makes you choose consciously up front.- Git is on by default.
kiri initrunsgit initand makes an initial commit unless you pass--no-git. Contracts are code; they live in version control from minute one. - New GitHub repos default to private. With
--github, the CLI creates the remote repo and pushes the initial commit so the scaffolded per-project CI runs immediately — and creates it private unless you explicitly pass--public. Data-warehouse projects are sensitive by default.
Useful variants:
# Wire an existing empty GitHub repo and push
kiri init acme-dw --silver-technique data_vault --adapter databricks \
--remote git@github.com:acme/acme-dw.git --push
# Choose the file layout (default: per_domain)
kiri init acme-dw --silver-technique data_vault --adapter databricks \
--layout per_source
Project layout
kiri init writes:
| Path | What it is |
|---|---|
kiri.yml | Project config: name, adapter, silver technique, targets. The single source of truth. |
sources/ | Source declarations — where data comes from |
contracts/ | Data contracts — the shape of data after Kirimana lands it |
models/ | Generated model output |
.kiri/ | Local state directory (gitignored) |
The source-vs-contract split is fundamental: a source describes where the data comes from; a contract describes the data shape after Kirimana lands it. One source can produce many contracts.
If you work across several projects, kiri use <directory> sets the
active one, kiri use shows it, and kiri use --clear forgets it.
Check where you stand at any time:
kiri project status
This prints the project identity, default target, and readiness
state. kiri targets lists the configured targets.
Fill in your workspace coordinates in kiri.yml (host, catalog,
warehouse_id) as described on the install page,
then confirm the wiring:
kiri databricks health --target dev
Scaffold your first contract
Create a contract for a source table:
kiri contract new --source crm --table customers --owner you@example.com
Note the explicit --owner. Ownership is a mandatory governance
field on every contract, and the scaffolders refuse to leave a
placeholder in charge — a contract without a real, accountable owner
is a contract nobody maintains. The same fail-closed posture runs
through the batch scaffolders (kiri scaffold bronze,
kiri scaffold silver, kiri scaffold mart): defaults that would
mask missing decisions are rejected rather than silently filled in.
The generated file lands in contracts/ as an ODCS-format YAML with
the governance fields (owner, classification, domain), the
column definitions, and a starting set of column-level expectations.
Open it and make it true: correct the types, describe the columns,
set the classification your data actually warrants.
Lint and validate
Two layers of checking, both cheap enough to run constantly:
# Validate one contract against the contract schema
kiri contract validate contracts/customers.yml
# Lint the whole project
kiri lint
# Validate the project's kiri.yml itself
kiri project validate
Run these before every commit. The scaffolded CI runs the same checks on every push, so a contract that doesn’t validate never reaches review. A typical branch flow looks like:
git checkout -b feature/new-customer-contract
kiri contract new --source crm --table customers --owner you@example.com
kiri contract validate contracts/customers.yml
kiri lint
git add contracts/customers.yml
git commit -m "feat(contracts): add customers contract"
git push origin feature/new-customer-contract
Plan, then apply
Never run blind against a workspace. kiri plan shows what an apply
would do — which sources fetch, which contracts compile, which
tables get created — with no destructive action:
kiri plan --target dev
When the plan looks right:
kiri apply --target dev
The apply:
- Fetches the declared source data.
- Materialises the bronze Delta table in your catalog, with
provenance columns (
_kiri_ingested_at,_kiri_trace_id) on every row. - Runs the contract’s expectations as tests — NOT NULL on keys, range checks, whatever the contract declares.
- Records the run, with a trace id, duration, and status.
Verify in the workspace UI: Catalog → your catalog → bronze — your table is there, with the rows and the provenance columns.
Read your first audit line
Every run Kirimana makes is written to an append-only JSONL audit log, and every SQL statement it issues carries the trace id as a SQL comment — so you can join Kirimana’s audit trail to the Databricks audit log after the fact.
Look at what your first apply left behind:
tail -1 logs/audit.jsonl
You’ll see a JSON object with the trace id, the operation, timing,
and outcome. This is the habit worth forming on day one: the audit
log is not a compliance afterthought bolted on later — it is written
on every run, from your very first apply, and the trace id on the
log line is the same trace id stamped into the _kiri_trace_id
column of the rows you just landed. One id, from CLI invocation to
warehouse row.
The log path defaults to ./logs/audit.jsonl relative to your
current working directory; set KIRIMANA_AUDIT_LOG_PATH to an
absolute path if you want a single log across projects.
Where to go next
- Iterate: edit the contract,
kiri plan,kiri apply— the loop is the workflow. - Deploy — AKS host + Databricks workspace when you’re ready to move from your laptop to a team deployment with a service principal and scheduled runs.