A well-designed Ontology creates a unified, intuitive representation of your organization that enables seamless data integration, cross-functional collaboration, and powerful analytics. This section provides both a quick-reference set of design guidelines and a deeper treatment of the core design principles that underpin them.
The following guidelines are a practical checklist for Ontology design. Where applicable, each one is grounded in a core design principle, anti-pattern, or structural recommendation.
These four principles are derived from extensive field experience across government and commercial implementations. They are presented in priority order. In cases of conflict, higher-priority principles take precedence.
| Priority | Principle | Core idea |
|---|---|---|
| 1 | Domain-driven design | Model the real world, not the source data. |
| 2 | Don't repeat yourself | If you built the same thing three times, refactor. |
| 3 | Open for extension, closed for modification | Protect core models. Enable builders to extend them. |
| 4 | Composition over deep hierarchies | Favor multiple inheritance via interfaces. Keep things pluggable. |
Practical considerations should always factor into any decision. Review the section on pragmatism and tradeoffs for more information.
The Ontology models the real world, not the source data.
Objects should represent semantically meaningful real-world concepts (such as a Patient, a WorkOrder, or a Vessel) not database tables, API responses, or spreadsheet tabs. Links should represent real relationships ("this patient visited this facility"), not join keys or foreign key artifacts.
When asked to "ontologize a dataset", resist the urge to map columns 1:1 to properties and consider the work complete. The Kitchen Sink anti-pattern produces an Ontology that mirrors source system schema quirks rather than useful semantics. A well-designed Ontology should feel intuitive to use; a user, or an AI agent, should be able to navigate it without friction, because the structure matches how they already think about their domain.
dtLastInspMod) rather than business language (lastInspectionDate)A CSV with columns order_id, customer_name, customer_email, product_sku, and quantity describes at least three real-world entities, not one:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
OrderData Order
- order_id - order_id
- customer_name - quantity
- customer_email → - Links to → Customer, Product
- product_sku
- quantity Customer
- name
(One object type mirroring the CSV) - email
Product
- sku
(Three object types modeling the domain)
| Problem | Impact |
|---|---|
| Unintuitive model | Users and AI agents cannot navigate the Ontology naturally because the structure does not match how they think about the domain. |
| Fragile coupling to source | Schema changes in source systems break Ontology consumers because the Ontology mirrors source structure rather than abstracting over it. |
| Missed relationships | Entities embedded as columns (like customer_name on an order) cannot be linked, searched, or reasoned about independently. |
| Poor reuse | Object types shaped by one system's schema are difficult for other teams or use cases to adopt. |
person.children over person.linkedChildPersonObjects. Prefer equipment.lastInspectionDate over equipment.dtLastInspMod.If you built the same thing three times, refactor.
Duplicated object types, redundant properties, and copy-pasted workflows are a maintenance burden and a context-management problem, for both humans and AI agents that need to reason about the Ontology. The goal is a single canonical representation for each concept, with a single canonical workflow for each operation on that concept. The rule of three is a practical trigger for applying this principle: one instance is a coincidence, two is a pattern, and three means it is time to refactor.
Three teams have independently created customer-related object types with overlapping schemas:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Sales Customer Customer (single canonical type)
- name - name
- email - email
- phone - phone
- sales_status
Support Customer → - support_tier
- name - billing_account_id
- email
- phone — OR, if shapes are genuinely distinct —
Billing Customer Interface: CustomerBase
- name - name
- email - email
- phone - phone
(Three types, three sets of actions, Implemented by: SalesLead, SupportContact,
three maintenance burdens) BillingAccount
| Problem | Impact |
|---|---|
| Maintenance burden | Changes must be replicated across every duplicate. Missed updates cause drift between copies. |
| Ambiguous context | Users and AI agents cannot determine which of several near-identical types is canonical. |
| Inconsistent behavior | Duplicated action or derived property logic diverges over time, producing conflicting results. |
| Wasted development effort | Teams re-build the same thing in slightly different forms instead of collaborating on one shared model. |
Protect core models. Enable builders to extend them.
Once an object type, interface, or workflow is field-tested and in production, its core structure should be stable. Other developers and teams in the organization should be able to build on top of it, adding new object types that implement an interface or new workflows that consume existing objects, without needing to modify the core model.
A core Equipment object type and Inspectable interface are in production. A new team needs to track certification data for some equipment:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Modify the core Equipment type: Extend without modifying core:
Equipment Equipment (unchanged)
- serial_number - serial_number
- manufacturer - manufacturer
- certification_authority (new) → - Links to → Equipment Certification
- certification_expiry (new)
- certification_status (new) Equipment Certification (new linked type)
- last_cert_audit (new) - certification_authority
- certification_expiry
(Four new properties, null for all - certification_status
non-certified equipment, existing - last_certification_audit
consumers must handle the change)
New interface: Certifiable
- certification_status
- certification_expiry
(Core type untouched, new capability
added via linked type and interface)
| Problem | Impact |
|---|---|
| Breaking changes | Modifications to core types can break dependent applications, actions, and workflows across the organization. |
| Scope creep | Core types accumulate properties and logic for every new use case, trending toward a God Object. |
| Entangled ownership | Multiple teams modify the same core type, creating merge conflicts and unclear accountability. |
| Security leakage | Extending a core type without clean boundaries can inadvertently widen data access. |
Favor multiple inheritance via interfaces. Keep things pluggable.
Foundry's Ontology supports multiple inheritance through interfaces, so an entity can compose behavior from multiple focused abstractions instead of a single-inheritance chain.
SchedulableBuilding or InspectableVehicle that merge two unrelated concepts into one typeAn Arena needs to be both a building and a schedulable resource:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Deep single-inheritance: Composed interfaces:
Asset Interface: Building
└── PhysicalAsset - address
└── Building - square_footage
└── SchedulableBuilding
└── Arena Interface: SchedulableResource
- scheduling_calendar
(Every new combination of capabilities - booking_policy
requires a new intermediate type.
A SchedulableWarehouse would need Arena implements both:
yet another branch.) Building + SchedulableResource
- arena_name
- seating_capacity
(Adding SchedulableWarehouse only
requires implementing the same two
interfaces — no new hierarchy needed.)
| Problem | Impact |
|---|---|
| Combinatorial explosion | Every new combination of capabilities requires a new intermediate type in the hierarchy. |
| Brittle hierarchies | Changes to a parent type cascade unpredictably through all descendants. |
| Limited reuse | Workflows built on a specific type deep in the chain cannot be reused for other types that share the same capability. |
| Semantic distortion | Contrived parent types (like SchedulableBuilding) do not represent real-world concepts, violating the domain-driven design principle. |
Inspectable, Schedulable, Billable, or Depreciable that capture a specific behavior or property set.MilitaryAsset implemented by Aircraft, Vessel, GroundVehicle) are particularly useful for drilldown investigations or similar aggregation workflows.SchedulableResource interface works for arenas, conference rooms, and vehicles without modification.These principles are guides, not laws.
Real-world constraints, including deadlines, legacy systems, partial platform support, and user skill levels, mean that the ideal Ontology design is not always immediately achievable. Use the following guidelines to navigate tradeoffs:
| Guideline | Detail |
|---|---|
| Steer toward good design without being a roadblock | If something needs to be working within a tight deadline, build something reasonable now with a clear path to improvement. |
| Name the tradeoffs explicitly | When recommending a shortcut, explain what is being traded away and when it might matter. For example, a denormalization could work fine at your current scale, but if you grow past 10k objects, you may want to revisit. |
| Prefer incremental improvement over big-bang refactors | A slightly imperfect Ontology that is in use and generating value is better than a theoretically perfect one that is still being designed. |
| Defend the critical invariants | Naming quality, semantic clarity, and security design are hard to fix later. Cut corners on implementation details, not on these. |
The Ontology is the software that powers your organization. Treat it with the same care you would give to a production codebase, but prioritize business value over perfection.