---
sidebar_position: 3
title: "Ontology system"
slug: /architecture/ontology-system
question: How should I model nouns versus verbs over time?

---

# Ontology system

The Ontology is the structural core of ABI. It integrates an organization's data, logic, and action capabilities into a formal, machine-readable representation that both humans and AI agents can reason over with precision.

Where conventional AI systems treat data as raw text fed into a context window, ABI models the operational world as typed entities and relationships. A sales motion is not a document to retrieve; it is a graph of Contacts, Accounts, Opportunities, and Acts of Partnership, with provenance, ownership, and time. An LLM operating on that graph does not guess at relationships; it reads them.

ABI builds its ontology on ISO and W3C open standards (BFO, OWL, RDF, SPARQL) that are independently specified and used across defense, healthcare, and intelligence. Your ontology is portable: exportable as Turtle files, importable into any RDF-compatible system, and not contingent on a vendor relationship.

---

## The Ontology Language, Engine, and Toolchain

The ontology system is not a thin semantic layer. It is a three-part architecture consisting of a Language, an Engine, and a Toolchain.

The **Language** is the formal vocabulary for modeling the world: OWL/Turtle files that define entity classes, properties, and relationships following the BFO hierarchy. The Language models both nouns (entities that persist through time: organizations, persons, products) and verbs (occurrents that unfold in time: acts of employment, partnership, acquisition). This separation is not academic; it determines how agents query and reason about time-varying operational data.

The **Engine** substantiates the Language at runtime, through the [triple store service](/architecture/services-and-adapters#triple-store). It provides the read architecture: SPARQL queries, streamed results for large ones, and subscriptions to triple patterns (`subscribe((s, p, o), callback)`) that call you back when matching triples are inserted or deleted. It provides the write architecture: `insert` and `remove` of triple sets from pipelines, integrations and event-driven sources, each change also published on the bus.

The **Toolchain** makes the Language and Engine accessible to developers. `onto2py` reads OWL Turtle files and emits typed Python classes (Pydantic models) alongside them, providing a single source of truth with no schema drift. Parameterized SPARQL templates (`TemplatableSparqlQuery`) let agents invoke graph queries as tools without writing Python. `abi new module` scaffolds an engine module (`--in-engine` in a NATS project) with its `ontologies/` folder (`modules/`, `processes/`, `queries/`) next to its agents, workflows and pipelines.

---

## The BFO 7 Buckets

BFO provides a practical mnemonic for building any domain ontology: the **7 Buckets**. Every entity in your knowledge graph belongs to one of seven categories. Learning to ask the right bucket question before modeling a concept is how experienced ontology engineers start.

| Bucket | BFO Category | Mnemonic question | Examples |
|---|---|---|---|
| **WHO** | Material Entity | Who is involved? | Organization, Person, Product, Physical asset |
| **WHERE** | Site | Where does it happen? | Country, Region, Office, Location |
| **WHAT** | Process | What happens? | Act of Partnership, Project, Task, Mission |
| **WHEN** | Temporal Region | When does it happen? | Fiscal Year, Calendar Year, Quarter, Date range |
| **HOW-WE-KNOW** | Information | How do we know? | Document, Report, LinkedIn page, Sector classification |
| **HOW-IT-IS** | Quality | How is it characterized? | Revenue, Language, Skill, Rating |
| **WHY** | Realizable Entity | What can it do or become? | Role, Service offering, Capability, Sales of product or service |

The key distinction is between **Occurrents** (WHAT, WHEN: things that happen, have temporal extent) and **Continuants** (the rest: things that persist). A process connects to the entities it involves via `has participant`; the time at which it occurs via `occupies temporal region`; the place where it unfolds via `occurs in`.

### Applying the 7 Buckets to a module

When you build a domain module, the ontology folder maps directly to the 7 Buckets. A professional services module might look like:

```
modules/professional-services/ontologies/
├── MaterialEntity/
│   ├── Organization/       ← firms, clients, subsidiaries
│   └── Person/             ← partners, staff, contacts
├── Site/
│   ├── Country/            ← jurisdiction
│   ├── Region/             ← Asia Pacific, EMEA ...
│   └── Location/           ← office addresses
├── Process/
│   ├── Mission/            ← strategic objectives
│   ├── Project/            ← engagement work
│   └── Task/               ← individual deliverables
├── TemporalRegion/
│   ├── FiscalYear/         ← firm financial year
│   └── CalendarYear/
├── Information/            ← Generically Dependent Continuant
│   └── Sectors/            ← industry classification applied to clients
│       ├── Consumer/
│       ├── LifeSciences/
│       └── Technology/
├── Quality/
│   ├── Languages/          ← spoken/written languages of staff
│   └── Skills/             ← professional competencies
└── Realizable/             ← what the firm can do or sell
    ├── Audit/
    ├── Tax/
    ├── Consulting/
    └── Legal/
```

The `onto2py` toolchain generates typed Python classes (Pydantic models) from each `.ttl` file in this structure. Agents operating on this ontology can answer questions like "which partners in the Asia Pacific region speak Mandarin and have skills in Tax?" — not by searching documents, but by traversing typed relationships across the knowledge graph.

---

## What is the knowledge graph?

The knowledge graph is a triple store: a database of subject-predicate-object statements (triples) stored in RDF format and queryable with SPARQL.

Instead of a schema like `table: organizations (id, name, website)`, the knowledge graph uses:

```turtle
<org/microsoft> rdf:type cco:CommercialOrganization .
<org/microsoft> abi:legalName "Microsoft Corporation" .
<org/microsoft> abi:hasLinkedInPage <page/microsoft-linkedin> .
```

This representation is:
- **Schema-flexible**: add new properties without migrations.
- **Relationship-native**: graph traversal is the default, not a join.
- **Reasoner-compatible**: OWL reasoners can infer new facts from axioms.
- **Interoperable**: RDF is an open standard; data can be exported, merged, or federated.

---

## The ontology hierarchy

ABI uses a layered ontology stack following the **Basic Formal Ontology (BFO)** standard (ISO/IEC 21838-2:2021). `naas-abi` ships the first three layers in `naas_abi/ontologies/imports/`:

| Layer | Files | What it adds |
|---|---|---|
| Top level (`top-level/`) | `bfo-core.ttl`, `BFO7BucketsProcessOntology.ttl` | Universal categories: continuant, occurrent, material entity |
| Mid level (`mid-level/`) | The Common Core Ontologies (CCO): agent, artifact, event, facility, geospatial, information entity, quality, time, units of measure and the rest | Concepts shared by every domain |
| Domain level (`domain-level/`) | Data source, geospatial, offering, time | Business concepts ABI's own modules use |
| Modules | Each module's `ontologies/`, for example `naas_abi/ontologies/modules/NaasAbiOntology.ttl` | What is specific to your domain |

Each layer extends the one above it.

### Why BFO?

BFO is an ISO standard used in defense, healthcare, finance, and intelligence. Grounding in BFO means:
- Your ontology is compatible with external datasets and standards.
- Reasoners behave predictably.
- You are not inventing naming conventions from scratch.

---

## Continuants vs. Occurrents

The most important BFO distinction:

| Category | Meaning | Examples |
|----------|---------|---------|
| **Continuant** | Things that persist through time | Person, Organization, Product, Role |
| **Occurrent** | Things that happen and unfold in time | Act of Employment, Partnership, Acquisition |

Within Continuants:
- **Material entity**: has mass, physically exists (Person, Organization, Factory)
- **Generically dependent continuant**: information that can be copied (Brand, Legal Name, LinkedIn Page, Website)
- **Realizable entity**: capacities and roles (Skill, Capability, Role, Service)

This isn't academic. It determines how agents query and reason about your data. An "Act of Partnership" is an occurrent that links two organizations (continuants) at a specific time. SPARQL queries that ask "who was a partner of X between 2023 and 2025" are straightforward when this structure is enforced.

---

## How ontologies become code: onto2py

ABI includes `onto2py`, a code generation tool that reads OWL Turtle files and emits typed Python classes (Pydantic models) alongside them. In the ABI repository, `make onto2py` regenerates the classes of every `.ttl` under `libs`.

```text
# Your ontology file
libs/naas-abi/naas_abi/ontologies/modules/
└── NaasAbiOntology.ttl

# onto2py generates next to it:
└── NaasAbiOntology.py   ← typed Pydantic classes, one per OWL class
```

This gives you a single source of truth: the `.ttl` file defines the RDF schema, and the generated `.py` file gives you type-checked Python access to ontology entities. No drift, no hand-written class definitions.

See [Creating an Ontology](/user-guide/build/knowledge-graph/creating-an-ontology) for usage.

---

## How agents use the knowledge graph

Agents interact with the knowledge graph in two ways:

1. **SPARQL queries as tools**: The built-in `naas_abi_core.modules.templatablesparqlquery` module turns parameterized SPARQL templates into agent tools, with no Python. A template is an individual of `TemplatableSparqlQuery` in a Turtle file (a module's `ontologies/queries/` holds them): its query text (Jinja2) and its arguments, each with a validation pattern. The module reads them from the triple store and builds one tool per query.

2. **Workflow queries**: Workflows call `services.triple_store.query(sparql)` on the engine directly (or `query_stream` for large results) and work with the rows, or with onto2py-generated classes.

---

## Supported triple store backends

The triple store is an engine service: `config.yaml` names its adapter under `services.triple_store`, and code never depends on the backend. The engine ships these adapters, with what each `abi new project` preset runs:

| Backend | `adapter:` | abi dev | Docker Compose | Remote |
|---|---|---|---|---|
| Oxigraph server (HTTP) | `oxigraph` | yes | — | — |
| Apache Jena Fuseki (TDB2) | `apache_jena_tdb2` | — | yes | yes |
| Amazon Neptune through an SSH bastion | `aws_neptune_sshtunnel` | — | — | — |
| Amazon Neptune | `aws_neptune` | — | — | — |
| RDF files on local disk | `fs` | — | — | — |
| Oxigraph embedded in the engine process | `oxigraph_embedded` | — | — | — |
| RDF files in an object storage service | `object_storage` | — | — | — |

Beyond the shipped adapters, the triple store takes `nats_rpc` (a client of the serving engine's triple store) and `custom` (your own class). [Services and adapters](/architecture/services-and-adapters#triple-store) gives each adapter's settings, where it keeps its data and its client library. Two decisions explain the defaults: [Oxigraph for local development](/user-guide/release-notes/oxigraph-local-triplestore) and [Apache Jena Fuseki for the Docker stack](/user-guide/release-notes/apache-jena-fuseki-default-triplestore).

In NATS mode the serving engine owns the store and serves it as a kernel service, so modules in other processes query it over NATS. A deploy that hands over without downtime needs a store every engine reaches (a server such as Oxigraph, Fuseki or Neptune), not an embedded or file-backed one: see [one serving engine](/architecture/real-time-fabric#one-serving-engine).

---

→ [Data plane](/architecture/data-plane)
