Template for building modular PMD Core application ontologies
Automated scaffolding, modular import architecture, SLME extraction, ROBOT templates, and Widoco documentation — all wired together with GitHub Actions.
- Overview
- Architecture
- Repository Structure
- Prerequisites
- Quick Start
- Configuration Files
- CI/CD Workflows
- Development Guide
- Import Architecture
- ID Range Allocation
- Troubleshooting
- Contributing
- License
This is a template repository for creating new Platform MaterialDigital (PMD) application ontologies. It provides:
- One-click setup — A single GitHub Actions workflow generates the entire ontology scaffold from configuration files
- Modular component system — Ontology content is organized into independent OWL modules (e.g.,
material_data,process_data) that share a common import backbone - Automated imports — External ontologies (PMD Core, LogO, TTO, HTO, etc.) are imported via SLME extraction so only referenced terms are included
- ROBOT template support — Define classes in simple TSV spreadsheets; they compile to OWL automatically
- Full CI/CD pipeline — Quality control, builds, import refresh, and documentation generation run on every push
- Auto-generated documentation — Widoco produces HTML docs deployed to GitHub Pages
Built on the Ontology Development Kit (ODK) v1.6 and runs entirely inside the obolibrary/odkfull Docker container — no local tooling required.
┌─────────────────────────┐
│ External Ontologies │
│ (pmdco, logo, tto, hto) │
└────────────┬────────────┘
SLME extraction
│
┌────────────▼────────────┐
│ *_import.owl modules │
│ (pmdco_import.owl, ...) │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ imports-edit.owl │
│ (aggregates all imports)│
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ {id}-shared.owl │
│ (shared import base) │
└────────────┬────────────┘
┌───────────┼───────────┐
│ │ │
┌──────▼──┐ ┌─────▼───┐ ┌─────▼───┐
│{id}- │ │{id}- │ │{id}- │
│material_ │ │process_ │ │sustain- │
│data.owl │ │data.owl │ │ability │ ... more components
└──────┬───┘ └────┬────┘ └────┬────┘
│ │ │
┌▼──────────▼────────────▼┐
│ {id}-axioms-shared.owl │
│ (top-level aggregation) │
└──────────────────────────┘
Each component module imports {id}-shared.owl, which transitively provides access to all external terms. The {id}-axioms-shared.owl file aggregates every component for the final build.
application-ontology-template/
│
├── .github/workflows/ # CI/CD pipeline (5 workflows)
│ ├── setup-repo.yml # Initial ontology scaffolding (22 steps)
│ ├── qc.yml # Build + quality control
│ ├── refresh-imports.yml # Re-extract external imports via SLME
│ ├── update-repo.yml # Sync repo structure from ODK config
│ └── docs.yml # Generate Widoco HTML documentation
│
├── component_seeds.txt # Component seed data (name|id|label|parent)
├── components.txt # Component module names (one per line)
├── creators.txt # Contributor names for ID range allocation
├── imports.txt # External ontology imports (id|url)
├── pmdco_terms.txt # PMD Core terms to import via SLME
│
├── project-odk.yaml # Main ODK configuration (auto-updated by setup)
├── seed-template.yaml # Minimal seed config template
│
├── LICENSE # Apache 2.0
└── README.md # You are here
After running the setup workflow, the following directories are generated:
├── src/
│ ├── ontology/
│ │ ├── {id}-edit.owl # Main ontology source (edit here)
│ │ ├── {id}-idranges.owl # ID allocation per contributor
│ │ ├── {id}-odk.yaml # Internal ODK config copy
│ │ ├── Makefile # ODK build system
│ │ ├── catalog-v001.xml # ROBOT import catalog
│ │ ├── imports/ # SLME-extracted import modules
│ │ │ ├── pmdco_import.owl
│ │ │ ├── logo_import.owl
│ │ │ └── ...
│ │ └── components/ # Modular OWL component files
│ │ ├── imports-edit.owl # Aggregates all *_import.owl
│ │ ├── {id}-shared.owl # Shared base (imports imports-edit)
│ │ ├── {id}-material_data.owl # Component module
│ │ ├── {id}-process_data.owl # Component module
│ │ └── {id}-axioms-shared.owl # Top-level aggregation
│ └── templates/ # ROBOT template TSV files
│ ├── {id}-material_data.tsv
│ └── {id}-process_data.tsv
└── src/ontology/config/
└── context.json # JSON-LD prefix context for ROBOT
| Requirement | Details |
|---|---|
| GitHub Account | With write access to this repository |
| GitHub Pages | Enabled in repo settings → Pages → Source: GitHub Actions |
| Actions Permissions | Settings → Actions → General → Read and write permissions + Allow GitHub Actions to create pull requests |
| No local tools needed | Everything runs in the obolibrary/odkfull:v1.6 Docker container via GitHub Actions |
For local development (optional): Install Protégé to edit OWL files, and Docker to run ODK locally via
make.
Click Use this template to create a new repository from this template.
Edit the following files in your new repo before running the setup workflow:
components.txt — Define your ontology modules
# One component name per line (no .owl extension)
material_data
process_data
sustainability_info
dismantling_data
component_seeds.txt — Pre-populate components with seed classes
# Format: ComponentName | ClassIRI | rdfs:label | ParentClassIRI
material_data | https://w3id.org/pmd/co/PMD_0000892 | portion of matter | http://purl.obolibrary.org/obo/BFO_0000040
process_data | https://w3id.org/pmd/co/PMD_0000907 | primary shaping | https://w3id.org/pmd/co/PMD_0000899
creators.txt — Register contributors for ID range allocation
Alice
Bob
Charlie
Each creator gets a block of 10,000 entity IDs (0–9999, 10000–19999, ...).
imports.txt — Add external ontology imports
# Format: import_id|direct_url_to_owl_file
# PMD Core (pmdco) is always imported automatically — don't add it here
logo|https://raw.githubusercontent.com/.../log-full.owl
tto|https://raw.githubusercontent.com/.../tto-full.owl
pmdco_terms.txt — Specify which PMD Core terms to import
# One IRI per line (comments with # are ignored)
https://w3id.org/pmd/co/PMD_0000833 # manufacturing process
https://w3id.org/pmd/co/PMD_0000892 # portion of matter
https://w3id.org/pmd/co/PMD_0000602 # Device
Go to Settings → Pages → Build and deployment → Source and select GitHub Actions.
Go to Settings → Actions → General → Workflow permissions:
- Select Read and write permissions
- Check Allow GitHub Actions to create and approve pull requests
- Navigate to Actions → Setup New Ontology
- Click Run workflow
- Fill in the parameters:
| Parameter | Example | Description |
|---|---|---|
ontology_id |
autoce |
Lowercase acronym for your ontology |
ontology_title |
Automotive Components Ontology |
Human-readable title |
id_digits |
7 |
Number of digits in entity IDs (default: 7) |
- Click Run workflow and wait for completion (~5–10 minutes)
Open src/ontology/{id}-edit.owl in Protégé or your preferred OWL editor.
Create new entities under the namespace https://w3id.org/pmd/{id}/ (e.g., AUTOCE_0000001).
The main ODK configuration file. Auto-generated by the setup workflow — manual edits will be overwritten during setup. Key sections:
| Section | Purpose |
|---|---|
id, title |
Ontology identifier and display name |
uribase, uribase_suffix |
IRI structure (https://w3id.org/pmd/{id}/) |
import_group.products |
External ontologies to import (SLME) |
components.products |
Modular OWL files registered for build |
idranges |
Entity ID blocks allocated per contributor |
ci: [] |
Disables ODK's default workflows (we use custom ones) |
Minimal bootstrap config used only if project-odk.yaml is missing. Defines the bare minimum for ODK seed to run.
Five GitHub Actions workflows automate the entire ontology lifecycle:
| Trigger | Manual dispatch (workflow_dispatch) |
| Steps | 22 steps end-to-end |
| What it does | Reads config files → configures ODK → seeds repo scaffold → creates import stubs → patches catalog → generates shared OWL backbone → extracts imports via SLME → creates ROBOT templates → injects annotations → validates → commits → triggers QC build |
| Container | obolibrary/odkfull:v1.6 |
| Trigger | Push to main / repository_dispatch: trigger-qc |
| What it does | Runs make test (reasoner + syntax checks) → make refresh-imports → builds release artifacts (OWL, TTL, JSON) → commits results → triggers docs |
| Trigger | Manual dispatch / repository_dispatch: trigger-refresh-imports |
| What it does | Re-downloads upstream ontologies and re-extracts SLME modules into imports/*_import.owl |
| Trigger | Manual dispatch / repository_dispatch: trigger-update-repo |
| What it does | Regenerates Makefile and config files from {id}-odk.yaml after manual config changes |
| Trigger | Manual dispatch / repository_dispatch: trigger-docs |
| What it does | Generates HTML documentation using Widoco and deploys to GitHub Pages |
setup-repo ──► qc (build) ──► docs (Widoco)
▲
push to main ───┘
- Open
src/ontology/{id}-edit.owlin Protégé - Create new classes under namespace
https://w3id.org/pmd/{id}/ - Push to
main— the QC workflow builds and validates automatically
Run these from src/ontology/:
make test # Run reasoner + validation checks
make refresh-imports # Re-extract external imports via SLME
make release # Build all release artifacts (OWL, TTL, JSON)
make update_repo # Regenerate Makefile from ODK config- Add the name to
components.txt - Re-run the Setup New Ontology workflow, or manually:
- Register in
project-odk.yamlundercomponents.products - Create the OWL file in
src/ontology/components/ - Add an
Import()for it in{id}-axioms-shared.owl - Run
make update_repo
- Register in
- Add a line to
imports.txt:myonto|https://example.org/ontologies/myonto.owl - Optionally create
myonto_terms.txtwith specific IRIs to extract - Run the Refresh Ontology Imports workflow
The setup workflow generates a layered OWL import graph that keeps modules decoupled while sharing external terms:
| File | Role |
|---|---|
imports/*_import.owl |
SLME-extracted modules from upstream ontologies |
imports-edit.owl |
Aggregates all *_import.owl into a single import point |
{id}-shared.owl |
Imports imports-edit.owl — shared base for all components |
{id}-{component}.owl |
Individual component modules — each imports {id}-shared.owl |
{id}-axioms-shared.owl |
Top-level aggregation importing ALL component files |
Why this structure?
- Each component gets all external terms through
{id}-shared.owlwithout redundant imports - Components are independently editable and testable
- Adding/removing a component only requires updating
{id}-axioms-shared.owl - The SLME extraction keeps import files minimal (only referenced terms)
Each contributor listed in creators.txt is allocated a 10,000 ID block:
| Creator | Range | Example ID |
|---|---|---|
| First | 0 – 9,999 |
AUTOCE_0000001 |
| Second | 10,000 – 19,999 |
AUTOCE_0010000 |
| Third | 20,000 – 29,999 |
AUTOCE_0020000 |
The ranges are encoded in {id}-idranges.owl (Manchester Syntax) and enforced by tools like dicer-cli.
Setup workflow fails at "Run ODK seed"
- Ensure
project-odk.yamlexists in the repo root - Check that
ontology_idcontains only alphanumeric characters - Review the stub import files — they must exist before ODK seed runs
ROBOT out-of-memory errors during SLME extraction
The workflows default to -Xmx8G. For very large upstream ontologies, increase the heap:
ROBOT_ENV='ROBOT_JAVA_ARGS=-Xmx12G'Double slashes in IRIs (e.g., /pmd//autoce/)
Step 12 of the setup workflow automatically normalizes these. If they persist:
find src/ontology -name "*.owl" -exec sed -i 's|/pmd//|/pmd/|g' {} +Catalog resolution errors (HTTP fetch during CI)
Ensure catalog-v001.xml has rewriteURI entries for both imports/ and components/ directories. Step 10 of setup does this automatically.
"Protected branch" error when pushing
The main branch requires pull requests. Push to a feature branch and open a PR:
git checkout -b feature/my-changes
git push origin feature/my-changesWe welcome contributions to the PMD Application Ontology Template!
- Issues: Report bugs or request features
- Discussions: Join community conversations
- PMD Playground Meetings: Every second Friday, 1–2 PM CET — Register via mailing list
- Contact: [email protected]
This project is licensed under the Apache License 2.0.