Adapted from docs/admin/OntologyManagement.md in the Wikantik repository; current as of release 2.4.56.
This guide is for curators, agent operators and developers who manage the ontology layer. Wikantik is a wiki with an ontology layered over it: the prose pages are also a machine-readable, queryable knowledge model. This guide explains why that exists and how to manage it day to day — as a human curator, as an AI agent, and as a developer evolving the vocabulary itself.
Terminology note: throughout, "ontology" means the
wikantik:RDF/OWL model — the classes, properties, and instances projected from the wiki. It is distinct from the Page Graph (page-to-page wikilink edges). See Page Graph vs Knowledge Graph — read it first if those two terms blur together.
A plain wiki stores prose. Wikantik additionally maintains a formal model of what the pages are about, because that unlocks things prose alone cannot:
knowledge-mcp tool surface — so an agent can traverse typed relations
and ask "what implements X" instead of grepping text. (The Knowledge Graph-aware search rerank was removed in 2026-07 — a 2026-06-16 ceiling experiment measured no net lift; see docs/archive/KnowledgeGraphRerank.md.)@type and sameAs are
re-sourced from the ontology, so the public structured data and the internal
model are two faces of one truth.Two concrete things the ontology makes possible that prose alone does not:
Ask the graph, don't grep the text. A keyword index maps terms to pages; the ontology maps concepts to one another, so you can ask structured questions — for example:
# Every technology that implements a given concept, with the page it's described on
PREFIX wk: <https://wiki.wikantik.com/ns/wikantik#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?tech ?label WHERE {
?tech a wk:Technology ; wk:implements ?concept ; rdfs:label ?label .
?concept rdfs:label "Distributed Consensus" .
}
Hit the public GET /sparql endpoint, dereference any resource at
/id/{type}/{id} as JSON-LD or Turtle, or let an agent traverse the same model
through knowledge-mcp (sparql_query, get_ontology) — none of which a
text index can answer.
Govern shared human + AI curation. Humans and agents both build the model through surfaces that read the same schema and pass the same write-time SHACL gate, provenance stamping, and audit log — so it converges under shared control instead of drifting between a human convention and an agent's guesses. The drift dashboard makes any remaining inconsistency measurable, and the burn-down workflow takes it to zero.
(Two more payoffs fall out of the same model: the wiki is interoperable linked
data — schema.org/SKOS/DC/PROV mappings + Turtle/N-Triples dumps consumable by
any RDF tool — and its SEO can't drift, because a page's public schema.org
@type is re-sourced from the ontology.)
It helps to see the ontology as three layers, because each is managed differently and by different people.
| Layer | What it is | Where it lives | Who manages it |
|---|---|---|---|
| 1. T-Box (vocabulary) | The class & property definitions — 9 entity classes, 5 content classes, 21 relation predicates, their domain/range, the schema.org/SKOS/DC/PROV mappings, and the SHACL shapes | wikantik-ontology/src/main/resources/ontology/wikantik.ttl + shapes.ttl; EntityTypeVocabulary, RelationshipTypeVocabulary, NodeTypeMapping (code) | Developers (edit Turtle/Java) |
| 2. Page concepts (A-Box) | Each page as a typed concept: its wk: content class, IRI, title/summary, and its tag/cluster SKOS concepts + provenance | Page frontmatter; projected by PageProjector + ConceptProjector | Authors & agents (the structured frontmatter editor) |
| 3. Knowledge Graph (A-Box) | The entities mentioned across the wiki (people, technologies, concepts, …) and the typed relations among them | kg_nodes / kg_edges; projected by EntityProjector + EdgeProjector | Extractors + curators (the Knowledge tab, admin panel, MCP tools) |
The vocabulary (Layer 1) is the closed set everything else conforms to:
person, organization, place, event, product, technology, concept, project, version.Hub, Article, Runbook, DesignDoc, Reference (mapped
from a page's type).related_to, part_of, contains, is_a, instance_of, generalizes, requires, enables, uses, produces, replaces, precedes, extends, implements, alternative_to, contrasts_with, compatible_with, mitigates, defines, applies_to, located_in.You author Layers 2 and 3; you don't author Layer 1 from the wiki — you create instances that conform to it. Changing the vocabulary is a code change (see Evolving the vocabulary below).
This is what most curation looks like, and it happens in the structured frontmatter editor — the form beside the Markdown body when you edit a page.
Full field reference: see
docs/user/Frontmatter.mdfor every supported frontmatter key, the editor's live-validation / Save-gating model, and the runbook block. This section covers only the ontology-relevant fields.
type (article / hub / reference / runbook / design)
maps to the page's wk: content class and its schema.org @type.cluster and each tag are
projected as skos:Concepts the page links to via dct:subject; sub-clusters
(parent/sub) become skos:broader relations. This is how the topical
hierarchy is modeled.verified_at / verified_by / audience feed the page's
trust/confidence and who-it's-for signals.canonical_id is the rename-stable ULID that becomes the page's ontology
IRI (/id/page/{canonical_id}). It's system-managed — read-only in the editor.The editor renders every field from a server-authoritative schema
(GET /api/frontmatter-schema) and validates against the same rules the server
enforces on save:
type/status, non-kebab cluster, and odd date formats warn (with a
one-click suggestion) but do not block — the corpus has legitimate drift,
and the model is meant to converge under shared control, not break existing
pages on edit. A dry-run endpoint (POST /api/frontmatter/validate) powers the
Raw-YAML break-glass tab.AI agents writing via the admin MCP update_page / write_pages tools hit the
same validator and receive the same suggestion-bearing messages, so they
can self-correct. See
docs/superpowers/specs/2026-06-08-structured-page-curation-design.md.
Layer-3 entities and relations come from two sources: automatic extraction and deliberate curation.
The entity extractors (chunk-level and page-level) read page content and emit
candidate entities (one of the 9 classes) and relations into kg_nodes /
kg_edges, stamped AI_INFERRED. This is the bulk-population path.
When you edit a page, the Knowledge tab (beside Frontmatter) shows the entities mentioned on that page and the relations among them, and lets you:
Writes go through /api/page-knowledge/*, gated by your edit permission on
the page, and route through the same curation facade as everything else — so the
SHACL gate, provenance stamping, and audit log all apply. A relation that
violates a shape is refused inline (HTTP 422) with the reason.
Curation only surfaces on KG-included pages. Inclusion is cluster-primary and default-exclude; use
kg_include: truein frontmatter to opt a page in. An entity curated on an excluded page won't appear in the slice. See KG Inclusion Policy.
/admin/knowledge-graph/* — list/query nodes & edges,
upsert, delete, merge duplicates, and review proposals.curate_nodes / curate_edges tools (and the
read-only knowledge-mcp retrieval tools) operate through the same
KgCurationOps chokepoint — there is no path that bypasses the SHACL gate or
provenance.Relations are validated against the SHACL shapes before they're written. The
gate is deliberately narrow today — implements requires a technology subject
and a concept object; located_in requires a place object — and a
non-conformant edge is refused (REST/MCP) or skipped-and-logged (the machine
materialization path), citing the violated shape. Predicates without a shape are
unconstrained. This is how the vocabulary's rules are enforced as the A-Box
grows under both human and AI hands.
The materialized model is queryable and dereferenceable, read-only and public (behind an ACL split so restricted pages/entities never materialize publicly):
/sparql (GET or POST) — read-only SELECT / ASK / CONSTRUCT (updates
rejected; result cap + timeout).GET /id/{type}/{id} — per-resource dereferencing as JSON-LD or Turtle
(e.g. /id/page/{canonical_id}, /id/entity/{uuid}).GET /export/ontology.ttl and /export/graph.nt — full dumps.knowledge-mcp exposes get_ontology (the formal T-Box) and
sparql_query (read-only SPARQL) to agents, plus ontology-aware query
expansion in the hybrid retriever (flag wikantik.search.ontologyExpansion.enabled,
default off).The RDF model is projected from PostgreSQL into a Jena TDB2 store with RDFS
subClassOf inference:
PageProjector (page concepts),
ConceptProjector (tag/cluster SKOS), EntityProjector + EdgeProjector
(KG entities/relations).OntologyEventListener re-projects a page's graph
(and its concept graphs) on save/rename and removes it on a true delete
(rename vs delete is disambiguated via canonical_id liveness). KgChangeEvent
now fires from both KG write funnels, and OntologyEntitySync re-projects
entity graphs incrementally too (coalesced, async); the nightly
OntologyRebuildScheduler is demoted to a reconciliation backstop./admin/ontology/rebuild, /admin/ontology/*
(status + SHACL-conformance violations); the store also rebuilds on startup if
empty.Config: wikantik.ontology.enabled (default true),
wikantik.ontology.tdb2.dir (blank by default, which means
<wikantik.workDir>/ontology-tdb2),
wikantik.ontology.rebuild.interval.hours (default 24, 0 = disabled),
wikantik.ontology.compaction.interval.hours (default 168, 0 = disabled; the
TDB2 store only grows between compactions, so keep this on),
wikantik.ontology.incremental.enabled (default true — event-incremental
entity sync; false restores nightly-only behavior), and
wikantik.ontology.incremental.coalesce.ms (default 500). Full
design: docs/superpowers/specs/2026-06-08-wiki-ontology-design.md.
When you genuinely need a new class, predicate, or constraint — a developer task, not a wiki edit:
Add/adjust the T-Box in wikantik.ttl (the class/property, its
rdfs:domain/rdfs:range, and any rdfs:subClassOf mapping to
schema.org/SKOS/DC/PROV). A class entry reads like:
wk:Technology rdfs:subClassOf wk:Entity ;
rdfs:subClassOf schema:SoftwareApplication .
wk:implements a owl:ObjectProperty ;
rdfs:domain wk:Technology ;
rdfs:range wk:Concept .
Update the code vocabularies so the extractors, validators, and UI agree:
EntityTypeVocabulary (the 9 entity classes), RelationshipTypeVocabulary
(the 21 predicates), and NodeTypeMapping (free-text type → wk: class +
schema.org type). Drift guards (e.g. EntityTypeVocabularyDriftTest) tie
these together — keep them green.
Tighten constraints by adding a shapes.ttl SHACL shape, which the
write-time gate will then enforce.
Surface the new value in the UIs that hardcode the vocab (the structured editor's enums, the Knowledge panel's type/predicate pickers).
The page-concept enums (type, status) are curated-open: new values are
tolerated (with a stern, suggestion-bearing warning) until the corpus is
normalized, then escalatable to hard errors via
wikantik.frontmatter.enum.nonCanonical.severity. This is the lever for evolving
the page vocabulary gradually under shared human/AI control.
Advisory warnings only matter if someone can see them in aggregate. The drift
dashboard (/admin/drift) makes vocabulary drift measurable:
(family, code, severity) — family frontmatter for field warnings, shacl for
non-conformant edges. Sweeps run automatically after each nightly ontology rebuild,
or on demand via the dashboard's Run sweep now (POST /admin/drift/sweep).wikantik.frontmatter.enum.nonCanonical.severity).The screen itself is described in Drift Dashboard. Endpoints: GET /admin/drift/summary, GET /admin/drift/trend?days=N,
GET /admin/drift/pages?family=F&code=C, GET /admin/drift/status (live sweep
progress for the dashboard's progress bar), POST /admin/drift/sweep.
The drift dashboard surfaces non-conformant edges under family shacl. Here is the
end-to-end loop to clear them — the same one used to take the corpus to zero.
See them. /admin/drift shows the shacl node-scoped count. Expand it (or
GET /admin/drift/pages?family=shacl&code=node-scoped) for the per-edge list;
each row names the focus node and the violated shape, e.g.
"wk:implements domain must be a wk:Technology."
Triage each one. A violation has two honest fixes — the call is per-entity:
concept), change its node_type to match; the edge
then conforms.implements pointing the wrong way),
delete it or re-predicate it.The question to ask is: is the subject really a technology, or is the
implements edge bogus?
Apply it through a curation surface — the admin panel
(/admin/knowledge-graph/*), the admin-MCP curate_nodes / curate_edges
tools, or, for a one-shot legacy cleanup of many rows, a direct SQL fixup (data
correction, not a versioned migration). Each surface keeps the SHACL gate,
provenance, and audit log in force for future writes.
Re-project. KG entity/edge edits fire a KgChangeEvent, which
OntologyEntitySync picks up and re-projects (coalesced, async — typically
settling within wikantik.ontology.incremental.coalesce.ms, default 500ms),
so most curation fixes reach the materialized model without a manual step.
If you want to force it (or the incremental sync is disabled via
wikantik.ontology.incremental.enabled=false), rebuild explicitly:
POST /admin/ontology/rebuild (or wait for the nightly reconcile). A
drift sweep fires automatically once a rebuild completes.
Re-sweep & confirm. If you didn't trigger a rebuild, run
POST /admin/drift/sweep and confirm the shacl count dropped to zero.
Preventing recurrence. The common cause was the entity extractor labelling a
real technology with an off-vocabulary type (database, framework, library,
tool, service, …) that fell back to concept — landing it under the
implements shape. The chunk and page extractors now resolve those synonyms to the
right class via EntityTypeVocabulary.TYPE_ALIASES, so freshly-extracted
technologies are typed correctly at the source.
Surfaces
| Purpose | Endpoint / tool |
|---|---|
| Field schema for the editor | GET /api/frontmatter-schema |
| Dry-run frontmatter validation | POST /api/frontmatter/validate |
| Page-scoped KG read + curation | /api/page-knowledge/{name} (view read, edit-gated writes) |
| KG admin (nodes/edges/proposals) | /admin/knowledge-graph/* |
| Ontology rebuild + status | /admin/ontology/* |
| Drift burn-down (sweep + counts) | /admin/drift/* |
| Public SPARQL | /sparql (GET or POST) |
| Resource dereferencing | GET /id/{type}/{id} (JSON-LD / Turtle) |
| RDF dumps | GET /export/ontology.ttl, /export/graph.nt |
| Agent tools | knowledge-mcp (get_ontology, sparql_query, retrieval); admin MCP (curate_nodes, curate_edges) |
Where the code lives
wikantik-ontologywikantik-main
(com.wikantik.knowledge.*), kg_* tableswikantik-api
(com.wikantik.api.frontmatter.schema), wikantik-main
(com.wikantik.frontmatter.schema), wikantik-frontendwikantik-restRelated docs
docs/user/Frontmatter.md — the full frontmatter field reference + the structured editordocs/archive/KnowledgeGraphRerank.md — the removed KG-aware retrieval rerank (historical)docs/superpowers/specs/2026-06-08-wiki-ontology-design.md — the RDF/OWL layer designdocs/superpowers/specs/2026-06-08-structured-page-curation-design.md — the editor + curation surfacesCluster Hub: Wikantik Platform Development Hub: Architecture, MCP Protocols, and Agent Briefings (wikantik-development)