Full source:
examples/ecommerce/Schema
Setup
setup.sql is idempotent: re-running it drops and recreates all tables in the correct order.
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.
Metrics
Guardrails
contracts/guardrails/ ships 3 contracts, not just the one refund filter:
revenue-excludes-refunds(mandatory_filter): AND-sstatus != 'refunded'into every query touchingorders.total_revenue. Expected revenue after the guardrail: 3790.50 (7 completed + 1 pending order. The seed data’s two refunded orders, totaling 260.00, never appear).board-final-only(restrict_source): in acontext: board_reportingquery, confinesrevenueto the finalorderssource only, excluding the intradayorders_rtestimates.finality-revenue: not a guardrail kind itself, but the paired finality ruleboard-final-onlyenforces: it declaresordersas thefinalrealization (watermarkbusiness_day - 1 day) andorders_rtasprovisional, withcoalescing: "window <= watermark ? final : provisional".
Example queries
query() for executable SQL + search_knowledge() for business context: both calls together, one decision. See Knowledge for how caveats auto-surface.
MCP server: stdio vs. HTTP
Stdio (the MCP client owns the process: Claude Code, Cursor):/mcp (SSE at /sse for clients that only support that). Only --transport http writes .canonic/mcp.json: in stdio mode the MCP client owns the process and no state file is created. --transport http is network-reachable, so it requires at least one auth mechanism: a bearer token (mcp.auth.tokens in canonic.yaml or --token-ref) and/or OAuth 2.1 (mcp.auth.oauth, for SSO-integrated organizations). See Connecting your agent for both.
Ingestion: keep semantics current
human_curated file (e.g. a column type changes), ingest flags a contradiction but keeps the curated file untouched. See Ingestion & reconciliation.
Evidence connectors beyond Postgres
Postgres introspection tells canonic what tables exist. connectors tell it what those tables mean:canonic ingest --connection warehouse_dbt --dry-run reconciles it into semantic proposals with no Postgres and no LLM: modeling-tier evidence outranks raw introspection where they overlap, and a genuine disagreement (e.g. conflicting column types) surfaces as a contradiction, never a silent merge.
To make the Notion evidence flow concrete without a live workspace, the demo ships five sample page sources at docs/notion-pages/, the format the Notion connector expects, including the two page properties it reads (Canonic Type → usage_mode, Canonic Topics → candidate topic refs).
Accuracy tracking
eval/grain_cases.jsonl exercise the shape of the live schema: a single surrogate key, a descriptive surrogate key, and a line-item fact where the grain is a single column rather than a composite key. See Instrumentation & evaluation.
CLI usage
Observability
served_answer event to the local, git-ignored event log. Every canonic ingest run appends reconcile_decision events to the same log. See Instrumentation & evaluation for exactly what is (and isn’t) recorded.
Air-gapped mode
air_gapped: true is a hard error at load. See LLM & embeddings runtime.
Knowledge pages
knowledge/global/ adds searchable business context on top of the semantic layer: