Open Ontologies is a Rust MCP server and desktop Studio for AI-native ontology engineering. It exposes 70+ tools that let Claude build, validate, query, diff, lint, version, reason over, align, plan, certify, and govern RDF/OWL ontologies using an in-memory Oxigraph triple store — with a full three-layer Dynamics → Causal → Planner architecture, a marketplace of 32 standard ontologies, clinical crosswalks, semantic embeddings, and a full lineage audit trail.

The Studio wraps the engine in a visual desktop environment: virtualized ontology tree with hierarchy lines, breadcrumb navigation, and connection explorer; AI chat panel with /build (IES-level deep) and /sketch (quick prototype) commands; Protégé-style property inspector; and lineage viewer.

No JVM. No Protégé.


What's New (three-layer architecture + 13 new primitives)

The full Dynamics → Causal → Planner stack plus 13 new primitives. Every piece holds the MCP-native convention: the server provides validation and scaffolding, the connected LLM (Claude over MCP) does the intelligence. No internal LLM clients, no API keys, no provider abstractions.

Three-layer architecture

Layer What it ships
Dynamics ActionSchema + 4 MCP tools: onto_action_register / _applicable / _apply / _list. Concurrent atomic ticks, static causal laws (invariants), default-value laws, ramification via OWL-RL closure, non-deterministic outcomes with reproducible seed.
Causal onto_certify_action with optional PyWhy backdoor identification (opt-in via causal-pywhy feature). Structural-proxy default + do-calculus opt-in + graceful fallback.
Planner onto_plan_compile_pddl + onto_plan_classical (Fast Downward subprocess) + onto_plan_validate (sandbox-simulate). Solver stays client-side; server compiles + validates.

13 new primitives

  • onto_owl_shacl_coevolve_check + onto_owl_shacl_coevolve_incremental — SHACL validation against the OWL-RL closure, with dependency-graph routing so only shapes touching changed IRIs revalidate.
  • onto_segment_retrieve — TBox-slice retrieval for ontology-grounded RAG.
  • onto_extract_scaffold + onto_extract_validate — schema-guided structured extraction with typed datatype validation + conformance scoring.
  • onto_cq_run + onto_verify_cq + onto_cq_verdicts_list — competency-question runner with pitfall hints + LLM-judgement loop.
  • onto_classify_el — OWL-EL classification (transitive subsumption table, trivial pairs excluded).
  • onto_eval_alignment — P/R/F1 over reference + computed alignment sets.
  • onto_shape_combinatorics + onto_shape_induce — property-combination lattice + data-driven SHACL shape induction with support × confidence ranking.
  • borderline_partition + borderline_record_verdict — generalised two-threshold review loop for any candidate set.
  • onto_align_fuzzy — embedding-free fuzzy-logic adjudication with 10-rule Mamdani inference; HNSW is demoted to a candidate generator.
  • onto_align_flora — end-to-end alignment pipeline pairing the signal extractor to the fuzzy adjudicator.
  • onto_policy_register + onto_policy_list + onto_policy_check — authorisation gate that composes with onto_certify_action (Causal = risk; policy = authorisation).
  • eval_rag + eval_rag_mmrag — Hit@k / MRR / faithfulness / token-Jaccard / ROUGE-1 scoring for retriever pipelines, with a dataset adapter.
  • graph_projection_lossy_check — the auditor that pairs with onto_segment_retrieve.

Validating end-to-end

cargo run --example three_layer_pipeline

Walks Dynamics register → PDDL compile → Fast-Downward-shaped sas_plan parse → orchestrator-side IRI bind → sandbox validate → CIVeX certify → apply with OWL-RL ramification → final state inspection. Every layer through its public API, no external dependencies (Python, DoWhy, Fast Downward) required.

Zero new external Rust dependencies; everything optional gates behind Cargo features. Full test suite (160+ tests) green on default build; cargo clippy --lib --tests --examples -- -D warnings clean across both default and causal-pywhy configurations.


Quick Start (MCP / CLI)

Install

Pre-built binaries:

# macOS (Apple Silicon)
curl -LO https://github.com/fabio-rovai/open-ontologies/releases/latest/download/open-ontologies-aarch64-apple-darwin
chmod +x open-ontologies-aarch64-apple-darwin && mv open-ontologies-aarch64-apple-darwin /usr/local/bin/open-ontologies

# macOS (Intel)
curl -LO https://github.com/fabio-rovai/open-ontologies/releases/latest/download/open-ontologies-x86_64-apple-darwin
chmod +x open-ontologies-x86_64-apple-darwin && mv open-ontologies-x86_64-apple-darwin /usr/local/bin/open-ontologies

# Linux (x86_64)
curl -LO https://github.com/fabio-rovai/open-ontologies/releases/latest/download/open-ontologies-x86_64-unknown-linux-gnu
chmod +x open-ontologies-x86_64-unknown-linux-gnu && mv open-ontologies-x86_64-unknown-linux-gnu /usr/local/bin/open-ontologies

Docker:

docker pull ghcr.io/fabio-rovai/open-ontologies:latest
docker run -i ghcr.io/fabio-rovai/open-ontologies serve

serve starts an MCP server that speaks JSON-RPC over stdin/stdout — it is not an interactive CLI, so on launch it will appear to "hang" while it waits for an MCP client to connect. That is expected. To try the tools directly from a terminal instead, use the CLI subcommands (e.g. open-ontologies validate <file.ttl>); to use it with an LLM, wire it into an MCP client as shown under Connect to your MCP client.

From source (Rust 1.85+):

git clone https://github.com/fabio-rovai/open-ontologies.git
cd open-ontologies && cargo build --release
./target/release/open-ontologies init

For native Windows builds, see docs/windows.md.

Connect to your MCP client

Add to ~/.claude/settings.json:

{
  "mcpServers": {
    "open-ontologies": {
      "command": "/path/to/open-ontologies/target/release/open-ontologies",
      "args": ["serve"]
    }
  }
}

Restart Claude Code. The onto_* tools are now available.

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "open-ontologies": {
      "command": "/path/to/open-ontologies/target/release/open-ontologies",
      "args": ["serve"]
    }
  }
}

Add to .cursor/mcp.json or equivalent:

{
  "mcpServers": {
    "open-ontologies": {
      "command": "/path/to/open-ontologies/target/release/open-ontologies",
      "args": ["serve"]
    }
  }
}
{
  "mcpServers": {
    "open-ontologies": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/fabio-rovai/open-ontologies", "serve"]
    }
  }
}

Build your first ontology

Build me a Pizza ontology following the Manchester University tutorial.
Include all 49 toppings, 24 named pizzas, spiciness value partition,
and defined classes (VegetarianPizza, MeatyPizza, SpicyPizza).
Validate it, load it, and show me the stats.

Claude generates Turtle, then runs the full pipeline automatically:

onto_validateonto_loadonto_statsonto_reasononto_statsonto_lintonto_enforceonto_queryonto_saveonto_version

Every build includes OWL reasoning (materializes inferred triples), design pattern enforcement, and automatic versioning.


Studio (Desktop App)

The Studio is a native desktop application that wraps the same engine in a visual environment — no browser, no server to manage. It runs entirely on your machine: the engine sidecar handles RDF/OWL operations while the UI renders the graph in real time.

Think of it as Protege meets an AI copilot. Type "build ontology about cats" and watch a 1,400-class ontology appear in the tree — classes, properties, individuals, and axioms built automatically across 13 pipeline steps. Click any node to inspect its triples, trace connections via clickable pills, and follow every change through the lineage panel.

Why virtualized tree (not 3D graph)

Prior to v0.1.12, the Studio used a D3.js horizontal tree and a 3D force-directed graph (Three.js / WebGL). Both worked for small ontologies (~100 classes) but became unusable at IES-level depth: the D3 tree couldn't handle 500+ nodes without layout thrashing, and the 3D graph froze the WebKit webview above 1,000 nodes.

The v2 deep builder changed the equation — a single /build command now produces 1,400+ classes. We replaced both views with a virtualized DOM tree: only visible rows exist in the DOM (constant memory regardless of ontology size), with hierarchy connector lines, type-filtered legend, search, breadcrumb navigation, and a connections panel. This handles the full IES Common (511 classes) and deep-built ontologies (1,400+ classes) without lag.

How it works

The Studio launches three processes that communicate locally:

  1. Tauri 2 shell — native window (macOS/Linux/Windows) with a WebKit webview
  2. Engine sidecar — the same Rust binary, running as an HTTP MCP server on localhost:8080
  3. Agent sidecar — Node.js process running Claude via the Agent SDK, connected to the engine over MCP

When you type in the chat panel, your message goes to the Agent sidecar, which sends it to Claude. Claude decides which onto_* tools to call, the engine executes them, and the UI refreshes the graph. The entire loop — prompt to visual update — takes seconds.

Install and run

Prerequisites: Rust + Cargo · Node.js 18+

# 1. Build the engine binary (from repo root)
cargo build --release

# 2. Install JS dependencies
cd studio && npm install

# 3. Run
PATH=/opt/homebrew/bin:~/.cargo/bin:$PATH npm run tauri dev

The first launch compiles the Tauri shell (~2 min). Subsequent launches start in seconds.

Features

Feature Description
Virtualized Tree Ontology explorer that handles 1,500+ classes without lag. Hierarchy connector lines, collapsible branches, type-filtered legend (Class/Property/Individual), search with auto-expand, breadcrumb path navigation, and a connections panel showing domain/range relationships as clickable pills. Only visible rows are in the DOM — constant memory regardless of ontology size.
AI Agent Chat Natural language ontology engineering via Claude Opus 4.8 + Agent SDK. Two build modes: /build runs a 13-step pipeline producing IES-level ontologies (500-1,500+ classes, 100-200+ properties), /sketch runs 3 steps for quick prototyping (~80 classes). Each tool call is shown in real time.
Property Inspector Protege-style inline triple editor. Click any node to see its rdfs:subClassOf, rdfs:label, rdfs:domain, rdfs:range and all other triples. Edit in place, hover to delete, + Add for new triples. Changes are immediately reflected in the graph.
Lineage Panel Full audit trail from SQLite: every plan, apply, enforce, drift, monitor, and align event, grouped by session with timestamps. See exactly what Claude did and in what order.
Named Save ⌘S to save as ~/.open-ontologies/<name>.ttl. Auto-saves to studio-live.ttl after every mutation so you never lose work.

Keyboard shortcuts

Shortcut Action
⌘J Toggle AI chat panel
⌘I Toggle property inspector
⌘S Save ontology
F Fit graph to viewport (tree view)
R Reset zoom (tree view)
Esc Deselect node
Shift+click Collapse/expand branch (tree view)
Scroll Zoom in/out
Click + drag Pan

Benchmarks

How to read these numbers. Unless stated, LLM results are single-run (not averaged over seeds) and use Claude Opus 4.8. Several benchmark ontologies (Pizza, FOAF, Schema.org, OWL-Time) are widely published and may appear in an LLM's pretraining data, so a bare-LLM score is a contamination-inclusive baseline, not a clean measure of reasoning — the contribution is the delta the MCP tools add on top of that baseline, and whether that delta reproduces across models. To check exactly that, the repo ships a cross-model ablation driving the same tasks with a local Qwen3-Coder-30B as well as Claude — see benchmark/ontoaxiom/. If the tool-augmented gain holds on a second, open model, the gain is a property of the tooling, not of one vendor's model.

OntoAxiom — LLM Axiom Identification

OntoAxiom tests axiom identification across 9 ontologies and 3,042 ground truth axioms.

All conditions below are scored by a single evaluator (benchmark/ontoaxiom/score_all_conditions.py) with one shared normalizer, and both averages are reported, because the original scripts disagreed on all of that. macro = mean of per-(ontology, axiom) F1; micro = F1 over pooled TP/FP/FN.

Approach Input macro F1 micro F1
o1 (paper's best) Name lists 0.197
Bare Claude Opus Name lists 0.451 0.397
Bare Qwen3-Coder-30B Name lists 0.223 0.176
Claude Opus, raw OWL file Full Turtle 0.768 0.686
Qwen3-Coder-30B, raw OWL file Full Turtle 0.673 0.667
MCP extraction Full OWL 0.713 0.717

The paper's "raw OWL hurts" result is a scoring artifact. OntoAxiom reports that an LLM given the full OWL file (F1 = 0.323) does worse than one given only class/property name lists (0.431). Those two numbers came from scripts that disagreed on three axes: the name-list scorer splits camelCase and the raw-OWL scorer only lowercases; the first reports a macro mean and the second a micro F1; and they flip pair order on different axiom types. Every one of those differences penalizes the raw-OWL condition, because that is the one where the model reads real Turtle and therefore answers in QNames (foaf:Person) and rdfs:label text ("personal mailbox" for mbox) rather than bare local names. 0.431 and 0.323 were never the same statistic.

Rescoring the same stored predictions under one evaluator flips the sign on both models and under both averages: Claude 0.451 → 0.768 macro (0.397 → 0.686 micro), Qwen 0.246 → 0.673 macro, winning 33/43 and 33/38 cells respectively. score_condition_d.py --legacy reproduces the broken 0.323 exactly, so the bug is demonstrated rather than asserted. The correction moves 0 of 5,083 name-list pairs, so it cannot flatter the baseline, and it still under-credits raw OWL: 51.8% of Claude's pairs are label text no normalizer here can match. Full analysis and reproduction: benchmark/ontoaxiom/ONTOAXIOM_SHOWDOWN.md.

Corrected, reading the ontology and SPARQL-extracting it are at parity — raw OWL wins macro (0.768 vs 0.713), extraction wins micro (0.717 vs 0.686). So the tools' edge is auditability, not F1: every MCP pair traces to a query against real triples, whereas an LLM reading a file can still hallucinate a plausible pair and no F1 score will say which.

Pizza Ontology — Manchester Tutorial

One sentence input: "Build a Pizza ontology following the Manchester tutorial specification."

Metric Reference (Protégé, ~4 hours) AI-Generated (~5 min) Coverage
Classes 99 95 96%
Properties 8 8 100%
Toppings 49 49 100%
Named Pizzas 24 24 100%

/sketch vs /build — Two Build Modes

The Studio provides two build commands for different use cases. Both take the same input — "build ontology about cats" — but produce very different results:

Metric /sketch (3 steps, ~2 min) /build (13 steps, ~15 min) IES Common (reference)
Classes 95 1,433 511
Object properties 15 218 162
Datatype properties 5 101 44
Individuals 3 358 21
Disjoints 6 60+
Max hierarchy depth 5 11 8
Build time ~2 min ~15 min — (hand-built)

/sketch runs 3 steps: classes + properties in one Turtle block, axioms + individuals, then save. Good for quick domain exploration or demo prototyping. Produces a complete ontology with hierarchy, properties, and individuals — but at a fraction of the depth.

/build runs a 13-step pipeline within a single persistent Claude session: foundation classes → per-branch deepening (4 passes) → gap filling → object properties (2 batches) → datatype properties → disjoints → individuals → reason → save. Each step focuses on one aspect of the ontology, staying within output token limits while building on the previous step's context. The result exceeds IES Common on every metric.

/sketch is comparable to the Pizza benchmark (95 classes, 8 properties). /build produces IES-level ontologies — deep enough for production use.

Mushroom Classification — OWL Reasoning vs Expert Labels

Dataset: UCI Mushroom Dataset — 8,124 specimens classified by mycology experts.

Metric Result
Accuracy 98.33%
Recall (poisonous) 100% — zero toxic mushrooms missed
False negatives 0
Classification rules 6 OWL axioms

Ontology Marketplace — 32 Standard Ontologies

All 32 marketplace ontologies fetched, owl:imports resolved, loaded, and reasoned over with both RDFS and OWL-RL profiles:

Ontology Classes Properties Triples + RDFS + OWL-RL Fetch RDFS OWL-RL
OWL 2 32 4 537 +230 +230 681ms 6ms 3ms
RDF Schema 6 0 87 +35 +35 522ms 2ms 1ms
RDF Concepts 7 0 127 +31 +31 545ms 2ms 2ms
BFO (ISO 21838) 35 0 1,221 +186 +186 1,141ms 5ms 4ms
DOLCE/DUL 93 118 1,917 +666 +692 2,208ms 13ms 12ms
Schema.org 1,009 0 17,823 +4,031 +13,670 558ms 57ms 117ms
FOAF 28 60 631 +4 +31 940ms 3ms 2ms
SKOS 5 18 252 +55 +55 218ms 2ms 1ms
Dublin Core Elements 0 0 107 +0 +0 371ms 2ms 1ms
Dublin Core Terms 22 0 700 +256 +261 259ms 4ms 3ms
DCAT 58 89 2,841 +223 +254 975ms 15ms 11ms
VoID 8 8 216 +0 +0 531ms 2ms 2ms
DOAP 17 0 741 +0 +0 727ms 2ms 2ms
PROV-O 39 50 1,146 +202 +203 472ms 5ms 4ms
OWL-Time 23 58 1,296 +165 +165 256ms 5ms 4ms
W3C Organization 22 33 748 +9 +21 639ms 4ms 3ms
SSN 35 38 1,815 +84 +84 519ms 6ms 4ms
SOSA 29 23 396 +0 +0 1,264ms 3ms 2ms
GeoSPARQL 12 54 796 +4 +12 733ms 3ms 3ms
LOCN 2 0 206 +0 +0 1,031ms 2ms 1ms
SHACL 40 0 1,128 +268 +268 662ms 5ms 3ms
vCard 75 84 882 +0 +46 854ms 3ms 3ms
ODRL 71 50 2,157 +73 +76 798ms 6ms 5ms
Creative Commons 6 0 115 +0 +49 184ms 1ms 1ms
SIOC 14 83 615 +0 +2 863ms 3ms 2ms
ADMS 4 13 151 +0 +0 747ms 3ms 1ms
GoodRelations 98 102 1,834 +15 +42 2,299ms 6ms 6ms
FIBO (metadata) 0 0 45 +0 +0 1,524ms 3ms 1ms
QUDT 73 175 2,434 +1,574 +1,581 2,934ms 14ms 9ms
Total 1,863 1,060 42,964 +8,111 +17,994

32/32 ontologies loaded, imports resolved, and reasoned. RDFS adds 18% more triples. OWL-RL adds 41% — transitive/symmetric/inverse properties and equivalentClass expansion discover significantly more implicit knowledge. Schema.org jumps from +4,031 (RDFS) to +13,670 (OWL-RL) inferred triples in 117ms.

Reasoning Performance — vs HermiT

LUBM Scaling (load + reason cycle)

Axioms Open Ontologies HermiT Speedup
1,000 15ms 112ms 7.5×
5,000 14ms 410ms 29×
10,000 14ms 1,200ms 86×
50,000 15ms 24,490ms 1,633×

Full benchmark writeup: docs/benchmarks.md

OAEI Ontology Alignment — Anatomy Track

OAEI is the standard benchmark for ontology alignment systems. The Anatomy track aligns 2,737 mouse anatomy classes to 3,304 human anatomy classes against 1,516 reference mappings.

System Precision Recall F1
AML 0.950 0.922 0.936
BERTMap 0.940 0.910 0.924
LogMap 0.930 0.890 0.912
OLaLa 0.900 0.880 0.890
Open Ontologies 0.963 0.733 0.832

Open Ontologies uses 7 weighted signals (label similarity, property/parent/instance/restriction/neighbourhood overlap, embedding similarity), stable 1-to-1 matching, and a label penalty when no structural evidence is available. No external background knowledge (UMLS, BioPortal) is used. See issues #8, #9, #10 for planned improvements.


IES Support

IES (Information Exchange Standard) is the UK National Digital Twin Programme's core ontology framework. It uses a 4D extensionalist (BORO) approach for modelling entities, events, states, and relationships. Open Ontologies supports the full IES stack — all three layers, SHACL shapes, and example datasets from the IES-Org GitHub repositories.

The IES Layers

The marketplace includes all three tiers of the IES framework:

onto_marketplace install ies-top     # ToLO — BORO foundations (~22 classes)
onto_marketplace install ies-core    # Core — persons, states, events (~131 classes)
onto_marketplace install ies         # Common — full ontology (511 classes, 206 properties)

Benchmark

Metric IES Common
Classes 511
Object properties 162
Datatype properties 44
Total properties 206
Triples loaded 4,041
+ RDFS inferred +3,094 (+77%)
Fetch time 911ms
RDFS reasoning 63ms
Lint issues 0

IES is the second-largest ontology in the marketplace by class count (after Schema.org). RDFS reasoning produces the richest inference gain of any non-general ontology — State, ClassOfEntity, and Event subclasses all generating deep transitive chains.

Example Data

Load IES example datasets directly from the official repositories:

onto_pull https://raw.githubusercontent.com/IES-Org/ont-ies/main/docs/examples/sample-data/event-participation.ttl
onto_pull https://raw.githubusercontent.com/IES-Org/ont-ies/main/docs/examples/sample-data/hospital.ttl
onto_pull https://raw.githubusercontent.com/telicent-oss/ies-examples/main/additional_examples/ship_movement.ttl

SHACL Validation

onto_pull https://raw.githubusercontent.com/IES-Org/ont-ies/main/docs/specification/ies-common.shacl
onto_shacl

Data Mapping: EPC → IES

The repo includes a sample of real UK Energy Performance Certificates (benchmark/epc/epc-sample.csv) with a mapping config that transforms tabular EPC data into IES-shaped RDF:

onto_load benchmark/generated/ies-building-extension.ttl
onto_ingest benchmark/epc/epc-sample.csv --mapping benchmark/epc/epc-ies-mapping.json
onto_reason --profile rdfs

This mirrors NDTP's actual pipeline: CSV → IES RDF → validate → reason → query.

IES Building Extension — Comparison with NDTP/IRIS

The repo includes an IES Building Extension built from the UK EPC data schema and building science fundamentals, using IES 4D patterns. It was built independently — without reference to any existing implementation — then compared against the NDTP/IRIS production building ontology used in government data pipelines.

Metric NDTP/IRIS (hand-built) Open Ontologies (AI-built)
Schema
Classes 244 525
Properties 34 104
Triples (raw) 1,346 3,229
Lint issues 2 0
Reasoning
RDFS inferred 621 662
Triples after RDFS 1,967 3,891
Max hierarchy depth 7 10
Avg hierarchy depth 2.89 2.02
EPC Coverage
EPC columns covered 18/36 (50%) 36/36 (100%)
4D Pattern
Complete triads (Entity+State+ClassOf) 14 129
Enumerated individuals 2 214

Built blind from the 105-column EPC schema, SAP methodology, and BORO 4D extensionalism — zero reference to the IRIS implementation. The two ontologies make different trade-offs: IRIS is more tightly curated with higher average hierarchy depth (2.89 vs 2.02), reflecting deliberate grouping by domain experts. Open Ontologies covers more of the EPC data schema and applies the BORO 4D pattern more systematically across the domain.

How the hierarchy emerges from building science

The ontology's depth (max 10 levels) is not hand-tuned — it follows the natural classification that building scientists use. The EPC data schema describes heating systems as flat text fields ("Condensing gas boiler with radiators"), but the underlying domain has layered structure:

graph TD
    HS[Heating System] --> CH[Central Heating]
    HS --> NC[Non-Central / Room Heating]

    CH --> WET[Wet Central Heating<br/><i>hydronic distribution</i>]
    CH --> WA[Warm Air Central Heating<br/><i>ducted air</i>]
    CH --> EC[Electric Central Heating<br/><i>storage / underfloor</i>]

    WET --> BB[Boiler-Based]
    WET --> HP[Heat Pump]
    WET --> DH[Community / District]

    BB --> CB[Combustion Boiler]
    BB --> CHP[Micro-CHP]

    CB --> GAS["Gas boiler"]
    CB --> OIL["Oil boiler"]
    CB --> LPG["LPG boiler"]
    CB --> COND["Condensing boiler"]
    CB --> COMBI["Combi boiler"]
    CB --> BACK["Back boiler"]

    HP --> ASHP["Air source"]
    HP --> GSHP["Ground source"]
    HP --> WSHP["Water source"]

    EC --> STOR["Storage heaters"]
    EC --> PNL["Panel heaters"]
    EC --> UF["Underfloor electric"]

    NC --> FIX[Fixed Room Heater]
    NC --> PORT[Portable Heater]

    FIX --> GROOM["Gas room heater"]
    FIX --> EROOM["Electric room heater"]
    FIX --> SFROOM["Solid fuel room heater"]

    style HS fill:#1a1a2e,color:#fff
    style CH fill:#16213e,color:#fff
    style NC fill:#16213e,color:#fff
    style WET fill:#0f3460,color:#fff
    style WA fill:#0f3460,color:#fff
    style EC fill:#0f3460,color:#fff
    style BB fill:#533483,color:#fff
    style HP fill:#533483,color:#fff
    style DH fill:#533483,color:#fff
    style CB fill:#e94560,color:#fff
    style CHP fill:#e94560,color:#fff

The same pattern applies to the building fabric — heat transfer physics dictates the grouping:

graph TD
    TE[Building Thermal Envelope] --> OP[Opaque Elements<br/><i>conduction-dominated</i>]
    TE --> TR[Transparent Elements<br/><i>radiation + conduction</i>]

    OP --> WALL[Walls]
    OP --> ROOF[Roofs]
    OP --> FLOOR[Floors]

    TR --> WIN[Windows]
    TR --> DOOR[Doors]

    WALL --> MAS[Masonry Walls<br/><i>thermal mass</i>]
    WALL --> FRM[Framed Walls<br/><i>stud bridges</i>]

    MAS --> CAV["Cavity wall"]
    MAS --> SOL["Solid brick"]
    MAS --> SND["Sandstone"]
    MAS --> GRN["Granite"]
    MAS --> COB["Cob"]

    FRM --> TF["Timber frame"]
    FRM --> SYS["System-built"]
    FRM --> PH["Park home"]

    ROOF --> PIT[Pitched Roof]
    ROOF --> FLT[Flat Roof]

    PIT --> COLD["Cold roof<br/><i>insulation at ceiling</i>"]
    PIT --> WARM["Warm roof<br/><i>insulation at rafter</i>"]
    PIT --> THATCH["Thatched"]

    WIN --> SGL["Single glazed"]
    WIN --> DBL["Double glazed"]
    WIN --> TPL["Triple glazed"]
    WIN --> SEC["Secondary glazing"]

    style TE fill:#1a1a2e,color:#fff
    style OP fill:#16213e,color:#fff
    style TR fill:#16213e,color:#fff
    style WALL fill:#0f3460,color:#fff
    style ROOF fill:#0f3460,color:#fff
    style FLOOR fill:#0f3460,color:#fff
    style WIN fill:#0f3460,color:#fff
    style DOOR fill:#0f3460,color:#fff
    style MAS fill:#533483,color:#fff
    style FRM fill:#533483,color:#fff
    style PIT fill:#533483,color:#fff
    style FLT fill:#533483,color:#fff

Each level in the tree is a real building science distinction — central vs room heating, hydronic vs warm air, combustion vs electric, masonry vs framed, cavity vs solid. An independent building scientist, given the same EPC data values, produces these same intermediate groupings (verified by clean-room reproduction). RDFS reasoning traverses these chains transitively, which is why a 10-level hierarchy generates 662 inferred triples from 3,229 raw.

EPC Column Coverage Benchmark

Both ontologies tested against 36 key EPC data columns — can each ontology receive and represent the data from that column?

Metric NDTP/IRIS Open Ontologies
EPC columns covered 18/36 (50%) 36/36 (100%)
Triples 1,346 3,229

Queries derived from published DESNZ/ONS EPC statistical reports — not from either ontology's class structure. Full benchmark: benchmark/epc/

Use onto_align to map it to other domain ontologies:

onto_load benchmark/generated/ies-building-extension.ttl
onto_align <other-ontology.ttl>

Hierarchy Enforcement — Automated Inference Improvement

The hierarchy enforce pack detects flat spots in any ontology and suggests intermediate grouping classes. This is the same process used to deepen the building extension — now codified as a repeatable tool:

onto_load my-ontology.ttl
onto_enforce --pack hierarchy
# → flags classes with >5 direct children
# → reports max depth, avg depth, hierarchy density

Tested on IES Common (511 classes), the tool found 24 flat spots. A clean-room agent — with no prior context — proposed 38 intermediate grouping classes based solely on the domain meaning of the flagged children:

graph LR
    subgraph Before["IES Common — before"]
        EP1[EventParticipant] --> P1["Prosecutor"]
        EP1 --> P2["Observer"]
        EP1 --> P3["Driver"]
        EP1 --> P4["Supplier"]
        EP1 --> P5["WeaponLocation"]
        EP1 --> P6["...52 direct children"]
    end

    subgraph After["IES Common — after hierarchy enforce"]
        EP2[EventParticipant] --> R[RoleInEvent]
        EP2 --> L[LocationInEvent]
        EP2 --> A[AssetInEvent]
        R --> LR2[LegalRole]
        R --> IR[InvestigativeRole]
        R --> CR[CommercialRole]
        LR2 --> Q1["Prosecutor"]
        LR2 --> Q2["Signatory"]
        IR --> Q3["Observer"]
        IR --> Q4["Investigator"]
        CR --> Q5["Supplier"]
        CR --> Q6["Negotiator"]
        L --> Q7["WeaponLocation"]
        L --> Q8["TargetLocation"]
        A --> Q9["VehicleUsed"]
    end

    style EP1 fill:#e94560,color:#fff
    style EP2 fill:#1a1a2e,color:#fff
    style R fill:#16213e,color:#fff
    style L fill:#16213e,color:#fff
    style A fill:#16213e,color:#fff
    style LR2 fill:#0f3460,color:#fff
    style IR fill:#0f3460,color:#fff
    style CR fill:#0f3460,color:#fff
Metric Before After Change
Classes 511 549 +38
RDFS inferred 3,094 3,422 +328 (+10.6%)

The same tool, applied to any ontology, produces the same kind of improvement. The intermediate classes emerge from domain knowledge — not from reference to any other implementation.

Further Reading

Topic Link
IES Ecosystem Demo docs/ies-ecosystem.md
SPARQL Examples docs/ies-examples.md
Building Alignment docs/ies-alignment.md

Tools

70+ tools organized by function — available as MCP tools (prefixed onto_) and CLI subcommands:

Category Tools Purpose
Core validate load save clear stats query diff lint convert status RDF/OWL validation, querying, and management
Repository repo_list repo_load Browse and load ontologies from configured [general] ontology_dirs directories
Cache cache_status cache_list cache_remove unload recompile On-disk N-Triples compile cache, idle-TTL eviction, per-name management (details)
Marketplace marketplace Browse and install 32 standard W3C/ISO/industry ontologies
Remote pull push import Fetch/push ontologies, resolve owl:imports
Schema import-schema sql-ingest Postgres + DuckDB → OWL + SQL → RDF ingest
Data map ingest shacl shacl_check vocab_check reason extend Structured data → RDF pipeline; vocab_check = closed-world check that generated data uses only ontology-declared terms (catches what open-world SHACL misses)
Versioning version history rollback Named snapshots and rollback
Lifecycle plan apply lock drift enforce monitor monitor-clear lineage Terraform-style change management with webhook alerts and OpenCheir governance integration
Alignment align align_feedback align_fuzzy align_flora Cross-ontology class matching with self-calibrating weights + fuzzy-logic adjudication and end-to-end signal-driven pipeline
HNSW hnsw_build Persisted HNSW indices (cosine + Poincaré) over class embeddings
Clinical crosswalk enrich validate_clinical ICD-10 / SNOMED / MeSH crosswalks (93-row sample ships in data/crosswalks.parquet; run python scripts/build_crosswalks.py to rebuild or extend)
Feedback lint_feedback enforce_feedback Self-calibrating suppression
Embeddings embed search similarity Dual-space semantic search (text + Poincaré structural)
Reasoning reason dl_explain dl_check classify_el Native OWL2-DL SHOIQ tableaux + OWL-EL classification
Dynamics action_register action_applicable action_apply action_list action_apply_concurrent invariant_register invariant_list invariant_remove invariant_check default_register default_apply Action schemas + concurrent atomic ticks + static causal laws + default values
Causal certify_action Four-verdict causal certificate (EXECUTE / REJECT / EXPERIMENT / ABSTAIN); optional causal-pywhy feature enables backdoor identification
Planner plan_compile_pddl plan_classical plan_validate Compile + validate on the server; solver (Fast Downward) is a client-side subprocess
Governance policy_register policy_list policy_check Authorisation rules; composes with certify_action
RAG segment_retrieve graph_projection_lossy_check TBox-slice retrieval + projection-loss auditor
Extraction extract_scaffold extract_validate Schema-guided structured-extraction prompt + validator
CQs cq_run verify_cq cq_verdicts_list Competency-question runner with pitfall hints + judgement loop
Shape induction shape_combinatorics shape_induce Property-combination lattice + data-driven SHACL induction
Borderline loop borderline_partition borderline_record_verdict Generalised two-threshold review pattern for any candidate set
SQL sync sql_sync_state sql_sync_reset sql_sync_states_list CDC watermark tracking for incremental SQL ingest
Evaluation eval_alignment eval_rag eval_rag_mmrag Alignment P/R/F1 + RAG Hit@k / MRR / faithfulness + dataset adapter

Architecture

Engine

flowchart TD
    subgraph Clients["Clients"]
        Claude["Claude / LLM\nMCP stdio"]
        CLI["CLI\nonto_* subcommands"]
        Studio["Studio\nHTTP REST"]
    end

    subgraph Server["Open Ontologies Server"]
        direction TB

        subgraph Transport["Transport Layer"]
            MCP_HTTP["MCP Streamable HTTP\n/mcp"]
            REST["REST API\n/api/query · /api/update\n/api/save · /api/load · /api/lineage"]
        end

        subgraph ToolGroups["70+ Tools"]
            direction LR
            Core["Core\nvalidate · load · save · clear\nstats · query · diff · lint\nconvert · status"]
            DataPipe["Data Pipeline\nmap · ingest · shacl\nreason · extend · import-schema"]
            Lifecycle["Lifecycle\nplan · apply · lock · drift\nenforce · monitor · lineage"]
            Advanced["Alignment + Clinical\nalign · crosswalk · enrich\nenrich · embed · search · similarity\ndl_explain · dl_check"]
            Version["Versioning\nversion · history · rollback"]
        end

        subgraph Core2["Core Engine"]
            GraphStore["Oxigraph Triple Store\nRDF/OWL in-memory\nSPARQL 1.1"]
            SQLite["SQLite\nlineage events\nversion snapshots\nlint/enforce feedback\nembedding vectors"]
            Reasoner["OWL2-DL Reasoner\nSHOIQ tableaux\nRDFS · OWL-RL"]
            Embedder["Embedding Engine\ntract-onnx (O