Quickstart
Five minutes, no credentials, no server. Everything below runs against a local DuckDB file that Ontologiq creates for you.
Install
Requires Python 3.11 or newer.
pip install "ontologiq[serve]" ontologiq-duckdb
The serve extra adds the MCP server and the action runtime. If you only
want the compiler, pip install ontologiq is enough.
Scaffold a project
ontologiq init shop
cd shop
You get a small e-commerce ontology:
shop/
├── ontologiq.yml # project config: name, adapter, connection, seeds
├── objects/
│ ├── customer.yml # identity, properties, state, relations
│ └── order.yml # …and a governed action
├── seeds/
│ └── ecommerce.sql # demo fixtures, so there is data to look at
├── .gitignore # target/, *.duckdb, .ontologiq/
└── README.md
Build
ontologiq build
compiled 2 views → target/
seeded: 2 statements
build OK: customer, order ready to query
build runs four steps: validate the YAML and every expression in it,
compile it to target/, apply the seed fixtures, and run the
resulting views into DuckDB.
Look at a record
ontologiq show customer --key 1
customer #1
customer_id: 1
email: ada@example.com
full_name: Ada Lovelace
country: UK
lifetime_value: 1240.50
state: active
state is not a column in the source table. It was computed from the
predicates you declared:
state:
active: last_seen >= now() - 90d
churned: last_seen < now() - 90d
else: prospect
Ask for a customer who has not been seen in months and you get churned.
Ask for an order and you also get the actions it accepts:
ontologiq show order --key 102
order #102
order_id: 102
total: 54.00
placed_at: 2026-07-29 11:10:57
state: open
actions:
cancel — roles: support; approval required; requires: state == 'open'
Query the views yourself
The compiled views are ordinary SQL, sitting in your warehouse:
duckdb ecommerce.duckdb -c 'SELECT "state", count(*) FROM "customer" GROUP BY 1'
┌──────────┬──────────────┐
│ state │ count_star() │
├──────────┼──────────────┤
│ active │ 3 │
│ churned │ 1 │
│ prospect │ 1 │
└──────────┴──────────────┘
Nothing is hidden: target/views/customer.sql contains exactly the SELECT
that was applied.
What was generated
target/
├── views/
│ ├── customer.sql # the SELECT, in your adapter's dialect
│ └── order.sql
├── catalog.json # the whole graph: objects, states, relations, actions
└── mcp/manifest.json # the tools an AI agent will see
target/ is generated and gitignored. The YAML is the source of truth.
Next
- Demo — connect an AI agent and watch it propose a governed action.
- Concepts — what identity, state and actions mean.
- CLI reference — every command and flag.