Skip to main content
A small but end-to-end canonic project: a Postgres connection, a four-source star schema (two facts, three dimensions), three canonical metrics, three guardrail contracts (a refund filter plus a finality-backed board-reporting restriction), and a companion dbt manifest demonstrating the definition-connector class. This is the broadest walkthrough of the full loop: bootstrap, serve, evidence connectors, accuracy tracking, and observability all in one place.
Full source: examples/ecommerce/

Schema

Setup

setup.sql is idempotent: re-running it drops and recreates all tables in the correct order.

Quickstart

Each step proves one Phase 1 exit criterion: 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-s status != 'refunded' into every query touching orders.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 a context: board_reporting query, confines revenue to the final orders source only, excluding the intraday orders_rt estimates.
  • finality-revenue: not a guardrail kind itself, but the paired finality rule board-final-only enforces: it declares orders as the final realization (watermark business_day - 1 day) and orders_rt as provisional, with coalescing: "window <= watermark ? final : provisional".

Example queries

A typical agent pattern is 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):
HTTP daemon (background process, multiple clients):
The server uses FastMCP’s Streamable HTTP transport at /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

Headless / CI: deterministic pipeline + auto-PR:
Example CI job:
If the live schema drifts from a 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:
This demo ships a compiled dbt manifest modeling the same star schema. 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 Typeusage_mode, Canonic Topics → candidate topic refs).

Accuracy tracking

The five cases in 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

Every query served appends a 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

The daemon never starts misconfigured: a public LLM endpoint or a remote secret ref under 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:
See Knowledge for the full retrieval and drift-detection model.