Skip to main content
An end-to-end canonic project on a vehicle rental service: one SQLite connection, five dimensions, three fact tables, nine metric contracts (three canonical), and one enforced guardrail. No external database required. The entire dataset lives in a single rental.db file.
Full source: examples/rental/

Schema

Seed data: 40 rentals (32 completed, 3 active, 2 confirmed, 2 cancelled, 1 no-show), 32 settled payments, 8 damage claims, across 20 customers, 15 vehicles, 5 locations.

Setup

Quickstart

canonic status, canonic ingest --bootstrap, canonic query, and canonic mcp start never call the LLM: every table here has a declared primary key, so grain is inferred deterministically. CANONIC_LLM_API_KEY only matters for canonic eval baseline, which explicitly benchmarks the configured model against eval/grain_cases.jsonl (a labeled set with primary keys withheld, to force drafting).

Metrics

contracts/metrics/ ships 9 metric contracts. Three are the canonical showcase bindings. The rest support the guardrail’s caveats and other reporting cuts.

Guardrail

contracts/guardrails/ ships one enforced guardrail, completed-rentals-only: rentals.total_base_revenue must never be summed without a status = 'completed' filter: active and cancelled rows have NULL in total_amount. Use payments.total_paid for financial reporting instead.
Cross-fact fanout (documented in a knowledge caveat, not a guardrail: none of the four guardrail kinds cover “reject a join between two fanning fact tables”, see Contracts & guardrails): joining damages to payments in a single query fans out both facts. Always bridge each independently through rentals.

Files