How it fits together

The format reference tells you what each field means. This page answers the question underneath it: what are the moving parts, and which power does each one hold?

The clearest way to see it is not as an architecture diagram but as five things running at the same time during the demo.

PartWhat it concretely isWhat it may do
The dataecommerce.duckdb — tables customers, ordersExist. Ontologiq never writes to them
The ontologyobjects/*.yml, compiled into SQL viewsSay what a row means
The AI agentClaude, connected to ontologiq serve over MCPRead, traverse, propose
The humanyou, running ontologiq approvals in a different terminalThe only one who may approve — and may also propose, via ontologiq propose
The operational systemops/webhook_listener.py in the demo; your OMS in productionThe only one that performs the change

Four actors, four different powers, and none of them holds another’s. That sentence is the whole design.

The sequence, on one order

Follow order 102 through the demo.

1. First there is only a row

In the orders table: order_id=102, fulfilled_at=NULL, dispute_opened_at=NULL. It means nothing yet. It is a row.

2. The ontology gives it meaning

order.yml declares that the row is an order object, identified by order_id, and that it is in state open when fulfilled_at is null. The compiler turns that into a CASE WHEN inside a SQL view. Order 102 now is open — it does not merely “have a null column”.

That looks cosmetic. It is not, and step 4 is why.

3. The agent sees only what the ontology declares

Start the server with ontologiq serve --role support and the agent receives seven tools: get_order, list_customer, traverse_order_customer, … and propose_order_cancel. It does not receive “run arbitrary SQL”.

It never sees email either: that property is sensitive: true, so the column is not even selected by the query. The value never leaves the database — this is withholding, not masking.

Start the same server with no --role and the propose_ tools are not listed at all. An agent cannot call what it cannot see.

The ontology is the agent’s entire universe. Whatever you did not declare does not exist for it.

4. The agent proposes, and stops

A user asks to cancel order 102. The agent calls propose_order_cancel, and three things happen:

And the agent gets back:

{
  "outcome": "pending_approval",
  "proposal_id": "35e91e17-db45-402a-a3a8-f6c8f5c7043a",
  "note": "A human must approve this proposal before anything happens. You cannot approve it yourself; report the proposal id to the user."
}

Nothing has happened. The operational system has not been touched. And there is no approve tool anywhere on the MCP surface, so there is no sequence of calls that gets the agent any further. That is not a rule in a prompt the model may decide to ignore — the channel does not exist.

This is where step 2 pays for itself. requires: state == 'open' is expressible only because state is a defined concept computed from live data. Without the entity model you could not write that line at all, and the action would be a webhook with a form attached.

5. A human decides, in a different process

In a separate terminal, one the model has no way to address:

ontologiq approvals list
35e91e17-db45-402a-a3a8-f6c8f5c7043a
  order.cancel  {"order_id": "102"}
  params: {"reason": "customer changed mind"}
  proposed by support (fernandodenitto) at 2026-08-01T12:12:36Z

You see exactly what was proposed, by which role, with which parameters. You approve — and here is the part that matters most:

The precondition is evaluated a second time. Hours can pass between a proposal and a signature, and records move. If the order shipped in the meantime:

the precondition 'state == 'open'' no longer holds (state is now 'fulfilled')
— nothing was executed

That gap between deciding and acting is where governance usually leaks. Closing it is most of why the runtime exists.

6. The operational system does the work

Only now does the webhook fire, at your system:

POST /orders/102/cancel
Idempotency-Key: 35e91e17-db45-402a-a3a8-f6c8f5c7043a
{
  "ontologiq": {
    "object": "order",
    "action": "cancel",
    "actor_role": "support",
    "actor_user": "fernandodenitto",
    "proposal_id": "35e91e17-db45-402a-a3a8-f6c8f5c7043a",
    "ontology_digest": "c0ecb26df9953592"
  },
  "identity": { "order_id": "102" },
  "params": { "reason": "customer changed mind" }
}

Ontologiq does not cancel the order. It tells your order-management system that someone authorised decided to, and attaches who proposed, who approved, and which version of the ontology governed the decision. Your system performs the cancellation.

The value, by subtraction

The honest way to judge each piece is to ask what breaks without it.

Without the entity and state model, you cannot write requires: state == 'open'. The rule “only cancel what has not shipped” ends up hardcoded inside the application — rewritten in every app and every agent, with no single place that says which version is correct.

Without the propose/approve split, you are back to handing the agent a write token and putting “do not cancel without asking” in the prompt. That is soft enforcement: it depends on the model choosing to comply, and under task momentum models demonstrably do not.

Without re-evaluating the precondition at execution, the agent proposes at 09:00, the order ships at 11:00, you sign at 14:00, and you have just cancelled a shipped order. This is the classic failure of approval systems.

Without the webhook boundary, Ontologiq would need write credentials to your operational systems — and nobody would install it. Needing write access to nothing is what makes it adoptable.

Why the data layer and the action layer are one tool

They look like two products: a semantic layer and a governance layer. They ship together for a precise technical reason.

The safety of an action depends on the model of the data. The precondition is a query against live data, evaluated twice, in the same logical step that fetches the record. If these were two separate systems, “is order 102 still open?” would become a question one service asks another over a network — and at that moment you have reopened exactly the gap you were trying to close.

Next