OntoRAG
OntoRAG is an ontology-first alternative to traditional Retrieval-Augmented Generation (RAG).
Instead of retrieving text fragments and hoping the LLM reasons correctly, OntoRAG:
- extracts explicit structure from documents,
- builds a governed knowledge graph (RDF),
- and uses LLMs only where they add value: proposal, extraction, interpretation.
The result is a system that is inspectable, auditable, evolvable, and usable beyond chat.
Why OntoRAG exists
Traditional RAG systems suffer from structural weaknesses:
- No explicit domain model
- No traceability from answers to sources
- No governance or evolution of knowledge
- Hidden schema inside prompts and embeddings
OntoRAG flips the model:
Baselines --> Documents --> DTOs --> Ontology --> Instances --> SPARQL --> MCP tools --> LLM reasoning
LLMs propose. Code decides. Humans govern.
Architecture overview
Baseline Ontologies (OWL/TTL)
|
+-- Ontology Catalog (register, browse, compose)
|
v
Schema Card (initial or evolved)
|
Documents --> DTOs (Document / Chunk)
|
+-- Ontology Extraction (LLM -> proposals)
| |
| v
+-- Schema Card (deterministic merge, origin-tracked)
|
+-- Instance Extraction (LLM -> RDF with provenance)
|
v
Knowledge Graph (TTL / SPARQL)
|
+-- SPARQL endpoint (local rdflib or Blazegraph)
+-- Knowledge MCP Server (graph tools for agents)
+-- Ontology MCP Server (catalog tools for agents)
Core concepts
1. Ontology catalog and baselines
Before processing any documents, you can seed OntoRAG with baseline ontologies -- existing OWL/RDFS vocabularies (FOAF, Schema.org, PROV-O, domain-specific schemas, etc.).
Baselines are registered in a catalog (a directory of TTL files with a JSON manifest). You can:
- register standard or custom ontologies,
- browse and search across all baselines,
- compose multiple baselines into an initial schema card.
Each class and property from a baseline carries an origin field (e.g., "foaf", "schema_org") so you always know where a term came from.
2. DTO-first ingestion
Documents are content-hashed (SHA-256) before any processing occurs. The document ID is derived from the hash, making ingestion content-addressable: the same file ingested from different paths or at different times produces the same document_id. If a document has already been ingested, the pipeline skips re-chunking automatically (--force to override).
Documents are then parsed using PageIndex (for PDFs and Markdown — hierarchical, reasoning-based section detection) with fallback text extraction for other formats. The result is stable DocumentDTO / ChunkDTO objects.
DTOs are:
- content-addressable (same content = same document ID, no re-processing),
- format-agnostic (PDF, Markdown, CSV, DOCX, HTML, EPUB, ...),
- persistent (stored as JSON + JSONL),
- replayable,
- provenance-aware (page, section, text snippet, source path).
They are the semantic checkpoint of the pipeline.
3. Ontology induction (proposal, not truth)
LLMs analyze DTO chunks and propose:
- candidate classes,
- datatype properties,
- object properties,
- events,
- merge/alias suggestions.
These are proposals, not production schema. The LLM sees the current schema card and is instructed to reuse existing terms before inventing new ones.
4. Schema Card
The Schema Card is a compact, deterministic JSON description of the current ontology:
{
"version": "2026-02-12T10:00:00Z",
"namespace": "http://my.org/ns/",
"classes": [
{"name": "Person", "description": "A human being.", "origin": "foaf"},
{"name": "Invoice", "description": "A commercial invoice.", "origin": "induced"}
],
"datatype_properties": [
{"name": "email", "domain": "Person", "range": "string", "description": "...", "origin": "foaf"}
],
"object_properties": [
{"name": "knows", "domain": "Person", "range": "Person", "description": "...", "origin": "foaf"}
],
"events": [],
"aliases": [
{"names": ["Person", "Agent"], "rationale": "FOAF uses both interchangeably"}
],
"warnings": []
}
It is:
- versioned (ISO timestamp),
- human-reviewable,
- origin-tracked (
"foaf","schema_org","induced", etc.), - used to guide all downstream extraction.
The merge is deterministic: classes and properties are deduplicated by normalized name, descriptions are merged (longer wins), and baseline origins are preserved.
5. Instance extraction with provenance
Given a stable schema card, OntoRAG extracts instances from documents:
- RDF instances typed to schema card classes
- datatype properties as literals
- object properties linking instances
- every fact linked to its source chunk via PROV-style mention nodes (quote, page, section)
No hallucinated facts, no orphan triples.
6. Knowledge graph backends
OntoRAG supports two modes:
- Local inspection: in-memory RDF via rdflib, served as a FastAPI SPARQL endpoint
- Production-grade: external SPARQL engines (Blazegraph, QLever, others)
Both are exposed via standard SPARQL (GET/POST /sparql).
7. MCP integration
OntoRAG provides two MCP servers:
Knowledge MCP (default port 9010) -- query the knowledge graph:
sparql_select/sparql_construct-- raw SPARQL queriesdescribe-- describe a resource by IRIlist_by_class-- find instances of a classoutgoing/incoming-- graph traversal
Ontology Catalog MCP (default port 9020) -- browse and compose baselines:
list_ontologies-- list registered baselinesinspect_ontology-- view classes/properties of a baselinesearch_classes/search_properties-- search across all baselinescompose-- merge selected baselines into a schema cardadd_ontology-- register a new baseline from TTL content
This allows LLM agents to both select their starting ontology and query the resulting knowledge graph.
8. OntoRAG Hub
The Hub is a GitHub-like infrastructure for ontology-driven RAG. It exposes the full pipeline as a web API with a clear data-sovereignty model:
User (browser / agent)
│
▼
OntoRAG Hub API (FastAPI)
│ GitHub OAuth login → JWT session
│
├── Ingest / Extract / Instances
│ │
│ ▼
│ User's private GitHub repo: {user}/ontorag-data
│ └── data/dto/ data/proposals/ data/instances/
│
└── Ontology Registry (central, shared)
└── schema cards → dynamic onto-mcp (near-zero storage)
Key principles:
-
User data stays in the user's GitHub account. DTOs, chunks, proposals, and instance TTLs are stored in a private repo (
ontorag-data) created automatically via the GitHub API. OntoRAG Hub never holds user documents on its own servers. -
Ontologies are centrally shared. Published schema cards live on the Hub server and can be referenced by any user for extraction or composition.
-
MCP servers are generated dynamically from the ontology structure alone. Since a schema card is just a small JSON file describing classes and properties, the resulting onto-mcp is nearly volume-less — it needs no user data, only the schema structure and SPARQL templates.
-
Content-addressable dedup applies at the Hub level too. Uploading the same file content twice (even from different users) produces the same
document_id, and the second ingest is skipped.
Installation
pip install -e .
Core dependencies (declared in pyproject.toml):
typer, requests, pydantic, rdflib, pageindex, pymupdf, python-dotenv, fastapi, uvicorn, fastmcp, EbookLib, html2text, httpx, PyJWT, python-multipart.
Configuration
Copy the example environment file and fill in your API key:
cp .example.env .env
OPENROUTER_API_KEY=...
OPENROUTER_MODEL=openai/gpt-4o-mini
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_APP_NAME=OntoRAG
OPENROUTER_SITE_URL=https://ontorag.github.io
# Optional: only needed for load-ttl / sparql-update commands
BLAZEGRAPH_ENDPOINT=http://localhost:9999/blazegraph/namespace/ontorag/sparql
CLI reference
All commands are available via ontorag <command> --help.
Ontology catalog commands
Register a baseline ontology:
ontorag register-ontology foaf ./ontologies/foaf.ttl \
--label "Friend of a Friend" \
--description "People, social networks, and their connections" \
--tags "social,people"
Copies the TTL file into the catalog directory, auto-detects the namespace, and registers it in catalog.json.
Create an initial schema card from baselines:
ontorag init-schema-card \
--baselines foaf,prov \
--out data/schema/schema_card.json \
--namespace http://my.org/ns/
Parses the selected OWL/TTL baselines, extracts classes and properties, and merges them into a single schema card with origin tracking.
Start the ontology catalog MCP server:
ontorag ontology-mcp --catalog ./data/ontologies --port 9020
Document processing commands
Ingest a document:
ontorag ingest data/raw/manual.pdf --out data/dto
ontorag ingest data/raw/handbook.epub --out data/dto
# Re-ingesting the same file is a no-op (content-hashed):
ontorag ingest data/raw/manual.pdf --out data/dto
# → SKIP ingest: already ingested (document_id=doc_..., hash=...)
# Force re-ingest:
ontorag ingest data/raw/manual.pdf --out data/dto --force
The file is content-hashed (SHA-256) before chunking. If the same content was already ingested, the command skips processing and reports the existing document ID. Use --force to re-ingest anyway.
Uses PageIndex for PDFs and Markdown (hierarchical section tree) with fallback text extraction for other formats (DOCX, HTML, CSV, EPUB, ...). Stores DocumentDTO + ChunkDTOs as JSON + JSONL.
Extract ontology proposals:
ontorag extract-schema \
--chunks data/dto/chunks/doc_x.jsonl \
--schema-card data/schema/schema_card.json \
--out data/proposals/doc_x.schema.json
Sends each chunk + the current schema card to the LLM. The LLM proposes new classes, properties, events, and merge suggestions. Per-chunk proposals are aggregated into a single document-level proposal.
Build schema card (deterministic merge):
ontorag build-schema-card \
--previous data/schema/schema_card.json \
--proposal data/proposals/doc_x.schema.json \
--out data/schema/schema_card.next.json
Deterministically merges the proposal into the existing schema card. Deduplicates by normalized name, normalizes datatype ranges, validates domain/range references, and accumulates aliases and warnings. New items get "origin": "induced".
Export schema to Turtle:
ontorag export-schema-ttl \
--proposal data/proposals/doc_x.schema.json \
--out data/schema/staging_schema.ttl \
--namespace http://my.org/ns/
Extract instances:
ontorag extract-instances \
--chunks data/dto/chunks/doc_x.jsonl \
--schema-card data/schema/schema_card.json \
--out-ttl data/instances/doc_x.instances.ttl
Extracts structured instances constrained to the schema card, then converts to RDF with PROV-style provenance (quote, page, section for every fact).
Knowledge graph commands
Upload TTL to Blazegraph:
ontorag load-ttl \
--file data/schema/staging_schema.ttl \
--graph urn:staging:schema
Execute a SPARQL UPDATE:
ontorag sparql-update --query-file queries/promote_schema.rq
Start the local SPARQL server:
ontorag sparql-server \
--onto data/schema/staging_schema.ttl \
--inst data/instances/doc_x.instances.ttl \
--port 8890
Endpoints:
GET/POST /sparql-- SPARQL queries (SELECT, ASK, CONSTRUCT, DESCRIBE)GET /health-- health check with triple countGET /stats-- SPARQL-based statisticsPOST /reload-- reload graph from files
Supports content negotiation: JSON, CSV, TSV, XML, Turtle, N-Triples, JSON-LD.
Start the knowledge MCP server:
# Local TTL backend
ontorag mcp-server \
--onto data/schema/staging_schema.ttl \
--inst data/instances/doc_x.instances.ttl
# Remote SPARQL backend
ontorag mcp-server \
--sparql-endpoint http://localhost:9999/blazegraph/namespace/ontorag/sparql
Hub commands
Start the Hub API server:
ontorag hub --port 8000
Required env vars: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, HUB_JWT_SECRET.
Hub API endpoints:
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /auth/login |
-- | Redirect to GitHub OAuth |
| GET | /auth/callback?code=... |
-- | Exchange code for JWT |
| GET | /auth/me |
JWT | Current user profile |
| POST | /api/ingest |
JWT | Upload & chunk a file (multipart) |
| POST | /api/extract-schema |
JWT | Run ontology induction |
| POST | /api/extract-instances |
JWT | Extract instances |
| GET | /api/documents |
JWT | List user's ingested documents |
| GET | /api/ontologies |
-- | List centrally registered ontologies |
| POST | /api/ontologies |
JWT | Publish a schema card as shared ontology |
| GET | /api/ontologies/{slug} |
-- | Get a schema card |
| GET | /api/mcp/{slug} |
-- | Dynamic MCP endpoint info |
User artifacts (DTOs, chunks, proposals, instances) are stored in the user's private ontorag-data GitHub repo. Ontologies are stored centrally on the Hub server.
End-to-end workflow
# 1. Register baseline ontologies
ontorag register-ontology foaf ./ontologies/foaf.ttl --label "FOAF"
ontorag register-ontology prov ./ontologies/prov-o.ttl --label "PROV-O"
# 2. Compose baselines into an initial schema card
ontorag init-schema-card --baselines foaf,prov \
--out data/schema/schema_card.json
# 3. Ingest a document
ontorag ingest data/raw/report.pdf --out data/dto
# 4. Extract ontology proposals (LLM sees FOAF/PROV terms, reuses them)
ontorag extract-schema \
--chunks data/dto/chunks/doc_*.jsonl \
--schema-card data/schema/schema_card.json \
--out data/proposals/report.schema.json
# 5. Review and merge proposals into the schema card
ontorag build-schema-card \
--previous data/schema/schema_card.json \
--proposal data/proposals/report.schema.json \
--out data/schema/schema_card.json
# 6. Export schema to Turtle
ontorag export-schema-ttl \
--proposal data/proposals/report.schema.json \
--out data/schema/staging_schema.ttl
# 7. Extract instances with provenance
ontorag extract-instances \
--chunks data/dto/chunks/doc_*.jsonl \
--schema-card data/schema/schema_card.json \
--out-ttl data/instances/report.instances.ttl
# 8. Inspect the graph locally
ontorag sparql-server \
--onto data/schema/staging_schema.ttl \
--inst data/instances/report.instances.ttl
# 9. Expose to LLM agents
ontorag mcp-server \
--onto data/schema/staging_schema.ttl \
--inst data/instances/report.instances.ttl
Origin tracking
Every class, property, and event in the schema card carries an origin field:
| Origin value | Meaning |
|---|---|
"foaf", "schema_org", ... |
Came from a registered baseline ontology |
"induced" |
Proposed by the LLM during ontology extraction |
"" (empty) |
Pre-existing item with unknown origin |
Origin is set when an item first enters the schema card and is preserved across merges. If a baseline defines Person and the LLM later proposes Person again, the baseline origin is kept.
Project structure
ontorag/
__init__.py
cli.py # Typer CLI (13 commands, incl. hub)
dto.py # DocumentDTO, ChunkDTO, ProvenanceDTO + content hashing
extractor_ingest.py # PageIndex doc parsing + fallback chunking
storage_jsonl.py # JSONL persistence for DTOs
ontology_extractor_openrouter.py # LLM schema proposal extraction
instance_extractor_openrouter.py # LLM instance extraction
proposal_aggregator.py # Merge per-chunk proposals into one
schema_card.py # Deterministic schema card merge (with origin)
proposal_to_ttl.py # Schema proposal -> OWL/RDFS Turtle
instances_to_ttl.py # Instance proposals -> RDF with provenance
blazegraph.py # Blazegraph REST API integration
sparql_server.py # FastAPI in-memory SPARQL endpoint
mcp_backend.py # SparqlBackend ABC + Local/Remote impls
mcp_server.py # Knowledge graph MCP server
mcp_client.py # Async SSE client for remote MCP
ontology_catalog.py # Baseline catalog + OWL/TTL converter
ontology_mcp.py # Ontology catalog MCP server
hub/
__init__.py
app.py # Hub FastAPI app (all routes)
auth.py # GitHub OAuth + JWT sessions
github_storage.py # Read/write artifacts to user's GitHub repos
models.py # Pydantic request/response models
app.py # Vercel-deployed ontology catalog API
data/
ontologies/
catalog.json # Ontology catalog manifest
*.ttl # Registered baseline ontologies
hub_ontologies/ # Central ontology registry (Hub)
What OntoRAG is not
- Not a vector-only RAG
- Not a black-box "AI magic" system
- Not a chatbot framework
OntoRAG is a knowledge engineering system with LLM assistance.
Status
This project is:
- experimental but functional,
- architecture-first,
- designed for research, enterprise prototyping, and public-sector semantics.
APIs may evolve, concepts will stabilize.
License
Apache 2.0
Philosophy
If the system cannot explain what it knows, where it comes from, and why it changed, it is not a knowledge system.
OntoRAG is built to make that explanation unavoidable.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ontorag-0.1.0.tar.gz.
File metadata
- Download URL: ontorag-0.1.0.tar.gz
- Upload date:
- Size: 158.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a948aa98421be0313d122bc0052edf13e2d00eab0c4d60e2adcdf4d4ec9f5a41
|
|
| MD5 |
b834baea4a57378c443ac927ab8aeb43
|
|
| BLAKE2b-256 |
518628753ff72da301476efc269012ecb1595a6fe5454e553194abaecf1403a8
|
Provenance
The following attestation bundles were made for ontorag-0.1.0.tar.gz:
Publisher:
release.yml on ontorag/ontorag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ontorag-0.1.0.tar.gz -
Subject digest:
a948aa98421be0313d122bc0052edf13e2d00eab0c4d60e2adcdf4d4ec9f5a41 - Sigstore transparency entry: 2475132787
- Sigstore integration time:
-
Permalink:
ontorag/ontorag@bc9552e6824fc63bba351408ab2a1af6f236658d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ontorag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc9552e6824fc63bba351408ab2a1af6f236658d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ontorag-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ontorag-0.1.0-py3-none-any.whl
- Upload date:
- Size: 68.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a3d2e7f401ebf0a571afb1289b2ca628d448fbdef3393fd5c0c16fce3d32ad0
|
|
| MD5 |
43a3c403a51dfd2f424cfee099efbd85
|
|
| BLAKE2b-256 |
ff8dd6c21cc46a0572aa7f999bfd3b8fe88235141949ba32874837b8426239c0
|
Provenance
The following attestation bundles were made for ontorag-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ontorag/ontorag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ontorag-0.1.0-py3-none-any.whl -
Subject digest:
2a3d2e7f401ebf0a571afb1289b2ca628d448fbdef3393fd5c0c16fce3d32ad0 - Sigstore transparency entry: 2475132898
- Sigstore integration time:
-
Permalink:
ontorag/ontorag@bc9552e6824fc63bba351408ab2a1af6f236658d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ontorag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc9552e6824fc63bba351408ab2a1af6f236658d -
Trigger Event:
push
-
Statement type: